Scippy

SCIP

Solving Constraint Integer Programs

cons_knapsack.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not 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  */
1021  SCIP* scip, /**< SCIP data structure */
1022  int nitems, /**< number of available items */
1023  SCIP_Longint* weights, /**< item weights */
1024  SCIP_Real* profits, /**< item profits */
1025  SCIP_Longint capacity, /**< capacity of knapsack */
1026  int* items, /**< item numbers */
1027  int* solitems, /**< array to store items in solution, or NULL */
1028  int* nonsolitems, /**< array to store items not in solution, or NULL */
1029  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1030  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1031  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1032  SCIP_Bool* success /**< pointer to store if an error occured during solving
1033  * (normally a memory problem) */
1034  )
1035 {
1036  SCIP_RETCODE retcode;
1037  SCIP_Real* tempsort;
1038  SCIP_Real* optvalues;
1039  int intcap;
1040  int d;
1041  int j;
1042  SCIP_Longint weightsum;
1043  int* myitems;
1044  SCIP_Longint* myweights;
1045  int* allcurrminweight;
1046  SCIP_Real* myprofits;
1047  int nmyitems;
1048  SCIP_Longint gcd;
1049  SCIP_Longint minweight;
1050  SCIP_Longint maxweight;
1051  int currminweight;
1052  SCIP_Longint greedycap;
1053  SCIP_Longint greedysolweight;
1054  SCIP_Real greedysolvalue;
1055  SCIP_Bool eqweights;
1056  SCIP_Bool isoptimal;
1057  const size_t maxsize_t = (size_t)(-1);
1058 
1059  assert(weights != NULL);
1060  assert(profits != NULL);
1061  assert(capacity >= 0);
1062  assert(items != NULL);
1063  assert(nitems >= 0);
1064  assert(success != NULL);
1065 
1066  *success = TRUE;
1067 
1068 #ifndef NDEBUG
1069  for( j = nitems - 1; j >= 0; --j )
1070  assert(weights[j] >= 0);
1071 #endif
1072 
1073  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1074 
1075  /* initializing solution value */
1076  if( solval != NULL )
1077  *solval = 0.0;
1078 
1079  /* produces optimal solution by following the table */
1080  if( solitems != NULL)
1081  {
1082  assert(items != NULL);
1083  assert(nsolitems != NULL);
1084  assert(nonsolitems != NULL);
1085  assert(nnonsolitems != NULL);
1086 
1087  *nnonsolitems = 0;
1088  *nsolitems = 0;
1089  }
1090 
1091  /* allocate temporary memory */
1092  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1093  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1094  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1095  nmyitems = 0;
1096  weightsum = 0;
1097  minweight = SCIP_LONGINT_MAX;
1098  maxweight = 0;
1099 
1100  /* remove unnecessary items */
1101  for( j = 0; j < nitems; ++j )
1102  {
1103  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1104  /* items does not fit */
1105  if( weights[j] > capacity )
1106  {
1107  if( solitems != NULL)
1108  {
1109  nonsolitems[*nnonsolitems] = items[j];
1110  ++(*nnonsolitems);
1111  }
1112  }
1113  /* items we does not want */
1114  else if( profits[j] <= 0.0 )
1115  {
1116  if( solitems != NULL)
1117  {
1118  nonsolitems[*nnonsolitems] = items[j];
1119  ++(*nnonsolitems);
1120  }
1121  }
1122  /* items which always fit */
1123  else if( weights[j] == 0 )
1124  {
1125  if( solitems != NULL)
1126  {
1127  solitems[*nsolitems] = items[j];
1128  ++(*nsolitems);
1129  }
1130  if( solval != NULL )
1131  *solval += profits[j];
1132  }
1133  /* all important items */
1134  else
1135  {
1136  myweights[nmyitems] = weights[j];
1137  myprofits[nmyitems] = profits[j];
1138  myitems[nmyitems] = items[j];
1139 
1140  /* remember smallest item */
1141  if( myweights[nmyitems] < minweight )
1142  minweight = myweights[nmyitems];
1143 
1144  /* remember bigest item */
1145  if( myweights[nmyitems] > maxweight )
1146  maxweight = myweights[nmyitems];
1147 
1148  weightsum += myweights[nmyitems];
1149  ++nmyitems;
1150  }
1151  }
1152 
1153  /* no item is left then goto end */
1154  if( nmyitems == 0 )
1155  {
1156  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1157 
1158  goto TERMINATE;
1159  }
1160  /* if all items fit, we also do not need to do the expensive stuff later on */
1161  else if( weightsum > 0 && weightsum <= capacity )
1162  {
1163  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1164 
1165  for( j = nmyitems - 1; j >= 0; --j )
1166  {
1167  if( solitems != NULL )
1168  {
1169  solitems[*nsolitems] = myitems[j];
1170  ++(*nsolitems);
1171  }
1172  if( solval != NULL )
1173  *solval += myprofits[j];
1174  }
1175 
1176  goto TERMINATE;
1177  }
1178 
1179  assert(minweight > 0);
1180  assert(maxweight > 0);
1181 
1182  if( maxweight > 1 )
1183  {
1184  /* determine greatest common divisor */
1185  gcd = myweights[nmyitems - 1];
1186  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1187  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1188 
1189  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1190 
1191  /* divide by greatest common divisor */
1192  if( gcd > 1 )
1193  {
1194  eqweights = TRUE;
1195  for( j = nmyitems - 1; j >= 0; --j )
1196  {
1197  myweights[j] /= gcd;
1198  eqweights = eqweights && (myweights[j] == 1);
1199  }
1200  capacity /= gcd;
1201  minweight /= gcd;
1202  }
1203  else
1204  eqweights = FALSE;
1205  }
1206  else
1207  {
1208  assert(maxweight == 1);
1209  eqweights = TRUE;
1210  }
1211 
1212  assert(minweight <= capacity);
1213 
1214  /* only one item fits, than take the best */
1215  if( minweight > capacity / 2 )
1216  {
1217  int p;
1218 
1219  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1220 
1221  p = nmyitems - 1;
1222 
1223  /* find best item */
1224  for( j = nmyitems - 2; j >= 0; --j )
1225  if( myprofits[j] > myprofits[p] )
1226  p = j;
1227 
1228  /* update solution information */
1229  if( solitems != NULL)
1230  {
1231  solitems[*nsolitems] = myitems[p];
1232  ++(*nsolitems);
1233  for( j = nmyitems - 1; j >= 0; --j )
1234  if( j != p )
1235  {
1236  nonsolitems[*nnonsolitems] = myitems[j];
1237  ++(*nnonsolitems);
1238  }
1239  }
1240  /* update solution value */
1241  if( solval != NULL )
1242  *solval += myprofits[p];
1243 
1244  goto TERMINATE;
1245  }
1246 
1247  /* all items have the same weight, than take the best */
1248  if( eqweights )
1249  {
1250  SCIP_Real addval;
1251 
1252  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1253 
1254  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1255 
1256  addval = 0.0;
1257  /* update solution information */
1258  if( solitems != NULL || solval != NULL )
1259  {
1260  SCIP_Longint i;
1261 
1262  /* if all items would fit we had handled this case before */
1263  assert((SCIP_Longint) nmyitems > capacity);
1264 
1265  /* take the first best items into the solution */
1266  for( i = capacity - 1; i >= 0; --i )
1267  {
1268  if( solitems != NULL)
1269  {
1270  assert(nonsolitems != NULL);
1271  solitems[*nsolitems] = myitems[i];
1272  ++(*nsolitems);
1273  }
1274  addval += myprofits[i];
1275  }
1276 
1277  if( solitems != NULL)
1278  {
1279  assert(nonsolitems != NULL);
1280 
1281  /* the rest are not in the solution */
1282  for( i = nmyitems - 1; i >= capacity; --i )
1283  {
1284  nonsolitems[*nnonsolitems] = myitems[i];
1285  ++(*nnonsolitems);
1286  }
1287  }
1288  }
1289  /* update solution value */
1290  if( solval != NULL )
1291  {
1292  assert(addval > 0.0);
1293  *solval += addval;
1294  }
1295 
1296  goto TERMINATE;
1297  }
1298 
1299  /* in the following table we do not need the first minweight columns */
1300  capacity -= (minweight - 1);
1301 
1302  /* we can only handle integers */
1303  if( capacity >= INT_MAX )
1304  {
1305  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1306 
1307  *success = FALSE;
1308  goto TERMINATE;
1309  }
1310  assert(capacity < INT_MAX);
1311 
1312  intcap = (int)capacity;
1313  assert(intcap >= 0);
1314  assert(nmyitems > 0);
1315  assert(sizeof(size_t) >= sizeof(int)); /* no following conversion should be messed up */
1316 
1317  /* this condition checks if we will try to allocate a correct number of bytes and do not have an overflow, while
1318  * computing the size for the allocation
1319  */
1320  if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (maxsize_t / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1321  {
1322  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1323 
1324  *success = FALSE;
1325  goto TERMINATE;
1326  }
1327 
1328  /* allocate temporary memory and check for memory exceeding */
1329  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1330  if( retcode == SCIP_NOMEMORY )
1331  {
1332  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1333 
1334  *success = FALSE;
1335  goto TERMINATE;
1336  }
1337  else
1338  {
1339  SCIP_CALL( retcode );
1340  }
1341 
1342  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1343  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only use for greedy solution
1344  */
1345  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1346  for( j = nmyitems - 1; j >= 0; --j )
1347  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1348 
1349  SCIPsortDownRealLongRealInt(tempsort, myweights, myprofits, myitems, nmyitems);
1350 
1351  /* initialize values for greedy solution information */
1352  greedysolweight = 0;
1353  greedysolvalue = 0.0;
1354  isoptimal = TRUE;
1355  greedycap = capacity + (minweight - 1);
1356 
1357  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1358 
1359  /* determine greedy solution */
1360  for( j = 0; j < nmyitems; ++j )
1361  {
1362  assert(myweights[j] <= greedycap);
1363 
1364  /* take all fitting items */
1365  if( myweights[j] + greedysolweight <= greedycap )
1366  {
1367  /* update greedy solution weight and value */
1368  greedysolweight += myweights[j];
1369  greedysolvalue += myprofits[j];
1370  continue;
1371  }
1372  else if( greedysolweight < greedycap )
1373  isoptimal = FALSE;
1374  break;
1375  }
1376  assert(greedysolweight > 0);
1377  assert(greedysolvalue > 0.0);
1378 
1379  /* greedy solution is optimal */
1380  if( isoptimal )
1381  {
1382  assert(greedysolweight == greedycap);
1383 
1384  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1385 
1386  greedysolweight = 0;
1387 
1388  /* update solution information */
1389  if( solitems != NULL)
1390  {
1391  /* take the first best items into the solution */
1392  for( j = 0; j < nmyitems; ++j )
1393  {
1394  /* take all fitting items */
1395  if( myweights[j] + greedysolweight <= greedycap )
1396  {
1397  solitems[*nsolitems] = myitems[j];
1398  ++(*nsolitems);
1399  greedysolweight += myweights[j];
1400  }
1401  else
1402  {
1403  nonsolitems[*nnonsolitems] = myitems[j];
1404  ++(*nnonsolitems);
1405  }
1406  }
1407  }
1408  /* update solution value */
1409  if( solval != NULL )
1410  {
1411  assert(greedysolvalue > 0.0);
1412  *solval += greedysolvalue;
1413  }
1414 
1415  SCIPfreeBufferArray(scip, &tempsort);
1416  SCIPfreeBufferArray(scip, &optvalues);
1417 
1418  goto TERMINATE;
1419  }
1420 
1421  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1422 
1423  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1424  * all values entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1425  * invalid, a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1426  * 'nmyitem' values
1427  */
1428  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1429  assert(myweights[0] - minweight < INT_MAX);
1430  currminweight = (int) (myweights[0] - minweight);
1431  allcurrminweight[0] = currminweight;
1432 
1433  /* fills first row of dynamic programming table with optimal values */
1434  for( d = currminweight; d < intcap; ++d )
1435  optvalues[d] = myprofits[0];
1436  /* fills dynamic programming table with optimal values */
1437  for( j = 1; j < nmyitems; ++j )
1438  {
1439  int intweight;
1440 
1441  /* compute important part of weight, which will be represented in the table */
1442  intweight = (int)(myweights[j] - minweight);
1443  assert(0 <= intweight && intweight < intcap);
1444 
1445  /* copy all nonzeros from row above */
1446  for( d = currminweight; d < intweight && d < intcap; ++d )
1447  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1448 
1449  /* update corresponding row */
1450  for( d = intweight; d < intcap; ++d )
1451  {
1452  /* if index d is smaller the the current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should
1453  * be 0
1454  */
1455  if( d < currminweight )
1456  {
1457  optvalues[IDX(j,d)] = myprofits[j];
1458  }
1459  else
1460  {
1461  SCIP_Real sumprofit;
1462 
1463  if( d - myweights[j] < currminweight )
1464  sumprofit = myprofits[j];
1465  else
1466  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1467 
1468  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1469  }
1470  }
1471  /* update currminweight */
1472  if( intweight < currminweight )
1473  currminweight = intweight;
1474 
1475  allcurrminweight[j] = currminweight;
1476  }
1477 
1478  /* update optimal solution by following the table */
1479  if( solitems != NULL)
1480  {
1481  d = intcap - 1;
1482 
1483  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1484 
1485  /* insert all items in (non-) solution vector */
1486  for( j = nmyitems - 1; j > 0; --j )
1487  {
1488  /* if we cannot find any item anymore which is in our solution stop, if the following condition holds this
1489  * means all remaining items does not fit anymore
1490  */
1491  if( d < allcurrminweight[j] )
1492  {
1493  /* we cannot have exceeded our capacity */
1494  assert((SCIP_Longint) d >= -minweight);
1495  break;
1496  }
1497  /* collect solution items, first condition means that no next item can fit anymore, but this does */
1498  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1499  {
1500  solitems[*nsolitems] = myitems[j];
1501  ++(*nsolitems);
1502 
1503  /* check that we do not have an underflow */
1504  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1505  d = (int)(d - myweights[j]);
1506  }
1507  /* collect non-solution items */
1508  else
1509  {
1510  nonsolitems[*nnonsolitems] = myitems[j];
1511  ++(*nnonsolitems);
1512  }
1513  }
1514 
1515  /* insert remaining items */
1516  if( d >= allcurrminweight[j] )
1517  {
1518  assert(j == 0);
1519  solitems[*nsolitems] = myitems[j];
1520  ++(*nsolitems);
1521  }
1522  else
1523  {
1524  assert(j >= 0);
1525  assert(d < allcurrminweight[j]);
1526 
1527  for( ; j >= 0; --j )
1528  {
1529  nonsolitems[*nnonsolitems] = myitems[j];
1530  ++(*nnonsolitems);
1531  }
1532  }
1533 
1534  assert(*nsolitems + *nnonsolitems == nitems);
1535  }
1536 
1537  /* update solution value */
1538  if( solval != NULL )
1539  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1540 
1541  SCIPfreeBufferArray(scip, &allcurrminweight);
1542 
1543  /* free all temporary memory */
1544  SCIPfreeBufferArray(scip, &tempsort);
1545  SCIPfreeBufferArray(scip, &optvalues);
1546 
1547  TERMINATE:
1548  SCIPfreeBufferArray(scip, &myitems);
1549  SCIPfreeBufferArray(scip, &myprofits);
1550  SCIPfreeBufferArray(scip, &myweights);
1551 
1552  return SCIP_OKAY;
1553 }
1554 
1555 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1556  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1557  * selected items
1558  */
1560  SCIP* scip, /**< SCIP data structure */
1561  int nitems, /**< number of available items */
1562  SCIP_Longint* weights, /**< item weights */
1563  SCIP_Real* profits, /**< item profits */
1564  SCIP_Longint capacity, /**< capacity of knapsack */
1565  int* items, /**< item numbers */
1566  int* solitems, /**< array to store items in solution, or NULL */
1567  int* nonsolitems, /**< array to store items not in solution, or NULL */
1568  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1569  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1570  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1571  )
1572 {
1573  SCIP_Real* tempsort;
1574  SCIP_Longint solitemsweight;
1575  SCIP_Real* realweights;
1576  int j;
1577  int criticalindex;
1578 
1579  assert(weights != NULL);
1580  assert(profits != NULL);
1581  assert(capacity >= 0);
1582  assert(items != NULL);
1583  assert(nitems >= 0);
1584 
1585  if( solitems != NULL )
1586  {
1587  *nsolitems = 0;
1588  *nnonsolitems = 0;
1589  }
1590  if( solval != NULL )
1591  *solval = 0.0;
1592 
1593  /* initialize data for median search */
1594  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1595  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1596  for( j = nitems - 1; j >= 0; --j )
1597  {
1598  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1599  realweights[j] = (SCIP_Real)weights[j];
1600  }
1601 
1602  /* partially sort indices such that all elements that are larger than the break item appear first */
1603  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1604 
1605  /* selects items as long as they fit into the knapsack */
1606  solitemsweight = 0;
1607  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1608  {
1609  if( solitems != NULL )
1610  {
1611  solitems[*nsolitems] = items[j];
1612  (*nsolitems)++;
1613  }
1614  if( solval != NULL )
1615  (*solval) += profits[j];
1616  solitemsweight += weights[j];
1617  }
1618  for( ; j < nitems && solitems != NULL; j++ )
1619  {
1620  nonsolitems[*nnonsolitems] = items[j];
1621  (*nnonsolitems)++;
1622  }
1623 
1624  SCIPfreeBufferArray(scip, &realweights);
1625  SCIPfreeBufferArray(scip, &tempsort);
1626 
1627  return SCIP_OKAY;
1628 }
1629 
1630 #ifdef SCIP_DEBUG
1631 /** prints all nontrivial GUB constraints and their LP solution values */
1632 static
1633 void GUBsetPrint(
1634  SCIP* scip, /**< SCIP data structure */
1635  SCIP_GUBSET* gubset, /**< GUB set data structure */
1636  SCIP_VAR** vars, /**< variables in knapsack constraint */
1637  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1638  )
1639 {
1640  int nnontrivialgubconss;
1641  int c;
1642 
1643  nnontrivialgubconss = 0;
1644 
1645  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1646 
1647  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1648  for( c = 0; c < gubset->ngubconss; c++ )
1649  {
1650  SCIP_Real gubsolval;
1651 
1652  assert(gubset->gubconss[c]->ngubvars >= 0);
1653 
1654  /* nontrivial GUB */
1655  if( gubset->gubconss[c]->ngubvars > 1 )
1656  {
1657  int v;
1658 
1659  gubsolval = 0.0;
1660  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1661 
1662  /* print GUB var */
1663  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1664  {
1665  int currentvar;
1666 
1667  currentvar = gubset->gubconss[c]->gubvars[v];
1668  if( solvals != NULL )
1669  {
1670  gubsolval += solvals[currentvar];
1671  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1672  }
1673  else
1674  {
1675  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1676  }
1677  }
1678 
1679  /* check whether LP solution satisfies the GUB constraint */
1680  if( solvals != NULL )
1681  {
1682  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1683  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1684  }
1685  else
1686  {
1687  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1688  }
1689  nnontrivialgubconss++;
1690  }
1691  }
1692 
1693  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1694 }
1695 #endif
1696 
1697 /** creates an empty GUB constraint */
1698 static
1700  SCIP* scip, /**< SCIP data structure */
1701  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1702  )
1703 {
1704  assert(scip != NULL);
1705  assert(gubcons != NULL);
1706 
1707  /* allocate memory for GUB constraint data structures */
1708  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1709  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1710  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1711  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1712 
1713  (*gubcons)->ngubvars = 0;
1714 
1715  return SCIP_OKAY;
1716 }
1717 
1718 /** frees GUB constraint */
1719 static
1721  SCIP* scip, /**< SCIP data structure */
1722  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1723  )
1724 {
1725  assert(scip != NULL);
1726  assert(gubcons != NULL);
1727  assert((*gubcons)->gubvars != NULL);
1728  assert((*gubcons)->gubvarsstatus != NULL);
1729 
1730  /* free allocated memory */
1731  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1732  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1733  SCIPfreeBuffer(scip, gubcons);
1734 
1735  return SCIP_OKAY;
1736 }
1737 
1738 /** adds variable to given GUB constraint */
1739 static
1741  SCIP* scip, /**< SCIP data structure */
1742  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1743  int var /**< index of given variable in knapsack constraint */
1744  )
1745 {
1746  assert(scip != NULL);
1747  assert(gubcons != NULL);
1748  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1749  assert(gubcons->gubvars != NULL);
1750  assert(gubcons->gubvarsstatus != NULL);
1751  assert(var >= 0);
1752 
1753  /* add variable to GUB constraint */
1754  gubcons->gubvars[gubcons->ngubvars] = var;
1755  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1756  gubcons->ngubvars++;
1757 
1758  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1759  if( gubcons->ngubvars == gubcons->gubvarssize )
1760  {
1761  int newlen;
1762 
1763  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1764  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1765  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1766 
1767  gubcons->gubvarssize = newlen;
1768  }
1769 
1770  return SCIP_OKAY;
1771 }
1772 
1773 /** deletes variable from its current GUB constraint */
1774 static
1776  SCIP* scip, /**< SCIP data structure */
1777  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1778  int var, /**< index of given variable in knapsack constraint */
1779  int gubvarsidx /**< index of the variable in its current GUB constraint */
1780  )
1781 {
1782  assert(scip != NULL);
1783  assert(gubcons != NULL);
1784  assert(var >= 0);
1785  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1786  assert(gubcons->ngubvars >= gubvarsidx+1);
1787  assert(gubcons->gubvars[gubvarsidx] == var);
1788 
1789  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1790  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1791  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1792  gubcons->ngubvars--;
1793 
1794  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1795  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1796  {
1797  int newlen;
1798 
1799  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1800 
1801  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1802  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1803 
1804  gubcons->gubvarssize = newlen;
1805  }
1806 
1807  return SCIP_OKAY;
1808 }
1809 
1810 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1811 static
1813  SCIP* scip, /**< SCIP data structure */
1814  SCIP_GUBSET* gubset, /**< GUB set data structure */
1815  SCIP_VAR** vars, /**< variables in knapsack constraint */
1816  int var, /**< index of given variable in knapsack constraint */
1817  int oldgubcons, /**< index of old GUB constraint of given variable */
1818  int newgubcons /**< index of new GUB constraint of given variable */
1819  )
1821  int oldgubvaridx;
1822  int replacevar;
1823  int j;
1824 
1825  assert(scip != NULL);
1826  assert(gubset != NULL);
1827  assert(var >= 0);
1828  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1829  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1830  assert(oldgubcons != newgubcons);
1831  assert(gubset->gubconssidx[var] == oldgubcons);
1832  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1833  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1834 
1835  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1836 
1837  oldgubvaridx = gubset->gubvarsidx[var];
1838 
1839  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1840  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1841 
1842  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1843  * replacement variable is given by old position of the deleted variable
1844  */
1845  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1846  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1847  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1848 
1849  /* add variable to the end of new GUB constraint */
1850  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1851  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1852 
1853  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1854  gubset->gubconssidx[var] = newgubcons;
1855  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1856 
1857  /* delete old GUB constraint if it became empty */
1858  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1859  {
1860  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1861 #ifdef SCIP_DEBUG
1862  GUBsetPrint(scip, gubset, vars, NULL);
1863 #endif
1864 
1865  /* free old GUB constraint */
1866  SCIP_CALL( GUBconsFree(scip, &gubset->gubconss[oldgubcons]) );
1867 
1868  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1869  if( oldgubcons != gubset->ngubconss-1 )
1870  {
1871  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1872  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1873 
1874  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1875  * replacement GUB is given by old position of the deleted GUB
1876  */
1877  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1878  {
1879  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1880  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1881  }
1882  }
1883 
1884  /* update number of GUB constraints */
1885  gubset->ngubconss--;
1886 
1887  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1888  * (because it was at the end of the GUB constraint array)
1889  */
1890  assert(gubset->gubconssidx[var] == newgubcons
1891  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1892  }
1893 #ifndef NDEBUG
1894  else
1895  assert(gubset->gubconssidx[var] == newgubcons);
1896 #endif
1897 
1898  return SCIP_OKAY;
1899 }
1900 
1901 /** swaps two variables in the same GUB constraint */
1902 static
1903 void GUBsetSwapVars(
1904  SCIP* scip, /**< SCIP data structure */
1905  SCIP_GUBSET* gubset, /**< GUB set data structure */
1906  int var1, /**< first variable to be swapped */
1907  int var2 /**< second variable to be swapped */
1908  )
1909 {
1910  int gubcons;
1911  int var1idx;
1912  GUBVARSTATUS var1status;
1913  int var2idx;
1914  GUBVARSTATUS var2status;
1915 
1916  assert(scip != NULL);
1917  assert(gubset != NULL);
1918 
1919  gubcons = gubset->gubconssidx[var1];
1920  assert(gubcons == gubset->gubconssidx[var2]);
1921 
1922  /* nothing to be done if both variables are the same */
1923  if( var1 == var2 )
1924  return;
1925 
1926  /* swap index and status of variables in GUB constraint */
1927  var1idx = gubset->gubvarsidx[var1];
1928  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1929  var2idx = gubset->gubvarsidx[var2];
1930  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1931 
1932  gubset->gubvarsidx[var1] = var2idx;
1933  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1934  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1935 
1936  gubset->gubvarsidx[var2] = var1idx;
1937  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1938  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1939 }
1940 
1941 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1942 static
1944  SCIP* scip, /**< SCIP data structure */
1945  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1946  int nvars, /**< number of variables in the knapsack constraint */
1947  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1948  SCIP_Longint capacity /**< capacity of knapsack */
1949  )
1950 {
1951  int i;
1952 
1953  assert(scip != NULL);
1954  assert(gubset != NULL);
1955  assert(nvars > 0);
1956  assert(weights != NULL);
1957  assert(capacity >= 0);
1958 
1959  /* allocate memory for GUB set data structures */
1960  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1961  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1962  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1963  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1964  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1965  (*gubset)->ngubconss = nvars;
1966  (*gubset)->nvars = nvars;
1967 
1968  /* initialize the set of GUB constraints */
1969  for( i = 0; i < nvars; i++ )
1970  {
1971  /* assign each variable to a new (trivial) GUB constraint */
1972  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1973  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1974 
1975  /* set status of GUB constraint to initial */
1976  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1977 
1978  (*gubset)->gubconssidx[i] = i;
1979  (*gubset)->gubvarsidx[i] = 0;
1980  assert((*gubset)->gubconss[i]->ngubvars == 1);
1981 
1982  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1983  if( weights[i] > capacity )
1984  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1985  }
1986 
1987  return SCIP_OKAY;
1988 }
1989 
1990 /** frees GUB set data structure */
1991 static
1993  SCIP* scip, /**< SCIP data structure */
1994  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
1995  )
1996 {
1997  int i;
1998 
1999  assert(scip != NULL);
2000  assert(gubset != NULL);
2001  assert((*gubset)->gubconss != NULL);
2002  assert((*gubset)->gubconsstatus != NULL);
2003  assert((*gubset)->gubconssidx != NULL);
2004  assert((*gubset)->gubvarsidx != NULL);
2005 
2006  /* free all GUB constraints */
2007  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2008  {
2009  assert((*gubset)->gubconss[i] != NULL);
2010  SCIP_CALL( GUBconsFree(scip, &(*gubset)->gubconss[i]) );
2011  }
2012 
2013  /* free allocated memory */
2014  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2015  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2016  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2017  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2018  SCIPfreeBuffer(scip, gubset);
2019 
2020  return SCIP_OKAY;
2021 }
2022 
2023 #ifndef NDEBUG
2024 /** checks whether GUB set data structure is consistent */
2025 static
2027  SCIP* scip, /**< SCIP data structure */
2028  SCIP_GUBSET* gubset, /**< GUB set data structure */
2029  SCIP_VAR** vars /**< variables in the knapsack constraint */
2030  )
2031 {
2032  int i;
2033  int gubconsidx;
2034  int gubvaridx;
2035  SCIP_VAR* var1;
2036  SCIP_VAR* var2;
2037  SCIP_Bool var1negated;
2038  SCIP_Bool var2negated;
2039 
2040  assert(scip != NULL);
2041  assert(gubset != NULL);
2042 
2043  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2044 
2045  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2046  for( i = 0; i < gubset->nvars; i++ )
2047  {
2048  gubconsidx = gubset->gubconssidx[i];
2049  gubvaridx = gubset->gubvarsidx[i];
2050 
2051  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2052  {
2053  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2054  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2055  }
2056  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2057  }
2058 
2059  /* checks for each GUB whether all pairs of its variables have a common clique */
2060  for( i = 0; i < gubset->ngubconss; i++ )
2061  {
2062  int j;
2063 
2064  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2065  {
2066  int k;
2067 
2068  /* get corresponding active problem variable */
2069  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2070  var1negated = FALSE;
2071  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2072 
2073  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2074  {
2075  /* get corresponding active problem variable */
2076  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2077  var2negated = FALSE;
2078  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2079 
2080  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2081  {
2082  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2083  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2084  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2085  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2086  SCIPvarGetName(var1), k,
2087  SCIPvarGetName(var2));
2088  }
2089 
2090  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2091  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2092  }
2093  }
2094  }
2095  SCIPdebugMsg(scip, " --> successful\n");
2096 
2097  return SCIP_OKAY;
2098 }
2099 #endif
2100 
2101 /** calculates a partition of the given set of binary variables into cliques;
2102  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2103  * were assigned to the same clique;
2104  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2105  * the preceding variables was assigned to clique i-1;
2106  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2107  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2108  */
2109 
2110 static
2112  SCIP*const scip, /**< SCIP data structure */
2113  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2114  int const nvars, /**< number of variables in the clique */
2115  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2116  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2117  SCIP_Real* solvals /**< solution values of all given binary variables */
2118  )
2120  SCIP_VAR** tmpvars;
2121  SCIP_VAR** cliquevars;
2122  SCIP_Bool* cliquevalues;
2123  SCIP_Bool* tmpvalues;
2124  int* varseq;
2125  int* sortkeys;
2126  int ncliquevars;
2127  int maxncliquevarscomp;
2128  int nignorevars;
2129  int nvarsused;
2130  int i;
2131 
2132  assert(scip != NULL);
2133  assert(nvars == 0 || vars != NULL);
2134  assert(nvars == 0 || cliquepartition != NULL);
2135  assert(ncliques != NULL);
2136 
2137  if( nvars == 0 )
2138  {
2139  *ncliques = 0;
2140  return SCIP_OKAY;
2141  }
2142 
2143  /* allocate temporary memory for storing the variables of the current clique */
2144  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2145  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2146  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2147  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2148  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2149  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2150 
2151  /* initialize the cliquepartition array with -1 */
2152  /* initialize the tmpvalues array */
2153  for( i = nvars - 1; i >= 0; --i )
2154  {
2155  tmpvalues[i] = TRUE;
2156  cliquepartition[i] = -1;
2157  }
2158 
2159  /* get corresponding active problem variables */
2160  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2161 
2162  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2163  * by nondecreasing number of cliques the variables are in
2164  */
2165  nignorevars = 0;
2166  nvarsused = 0;
2167  for( i = 0; i < nvars; i++ )
2168  {
2169  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2170  {
2171  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2172  varseq[nvars-1-nignorevars] = i;
2173  nignorevars++;
2174  }
2175  else
2176  {
2177  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2178  varseq[nvarsused] = i;
2179  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2180  nvarsused++;
2181  }
2182  }
2183  assert(nvarsused + nignorevars == nvars);
2184 
2185  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2186  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2187 
2188  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2189 
2190  /* calculate the clique partition */
2191  *ncliques = 0;
2192  for( i = 0; i < nvars; ++i )
2193  {
2194  if( cliquepartition[varseq[i]] == -1 )
2195  {
2196  int j;
2197 
2198  /* variable starts a new clique */
2199  cliquepartition[varseq[i]] = *ncliques;
2200  cliquevars[0] = tmpvars[varseq[i]];
2201  cliquevalues[0] = tmpvalues[varseq[i]];
2202  ncliquevars = 1;
2203 
2204  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2205  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2206  */
2207  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2208  {
2209  /* greedily fill up the clique */
2210  for( j = i + 1; j < nvarsused; ++j )
2211  {
2212  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2213  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2214  {
2215  int k;
2216 
2217  /* check if every variable in the actual clique is in clique with the new variable */
2218  for( k = ncliquevars - 1; k >= 0; --k )
2219  {
2220  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2221  cliquevalues[k], TRUE) )
2222  break;
2223  }
2224 
2225  if( k == -1 )
2226  {
2227  /* put the variable into the same clique */
2228  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2229  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2230  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2231  ++ncliquevars;
2232  }
2233  }
2234  }
2235  }
2236 
2237  /* this clique is finished */
2238  ++(*ncliques);
2239  }
2240  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2241 
2242  /* break if we reached the maximal number of comparisons */
2243  if( i * nvars > maxncliquevarscomp )
2244  break;
2245  }
2246  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2247  for( ; i < nvars; ++i )
2248  {
2249  if( cliquepartition[varseq[i]] == -1 )
2250  {
2251  cliquepartition[varseq[i]] = *ncliques;
2252  ++(*ncliques);
2253  }
2254  }
2255 
2256  /* free temporary memory */
2257  SCIPfreeBufferArray(scip, &sortkeys);
2258  SCIPfreeBufferArray(scip, &varseq);
2259  SCIPfreeBufferArray(scip, &tmpvars);
2260  SCIPfreeBufferArray(scip, &tmpvalues);
2261  SCIPfreeBufferArray(scip, &cliquevalues);
2262  SCIPfreeBufferArray(scip, &cliquevars);
2263 
2264  return SCIP_OKAY;
2265 }
2266 
2267 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2268 static
2270  SCIP* scip, /**< SCIP data structure */
2271  SCIP_GUBSET* gubset, /**< GUB set data structure */
2272  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2273  SCIP_Real* solvals /**< solution values of all knapsack variables */
2274  )
2275 {
2276  int* cliquepartition;
2277  int* gubfirstvar;
2278  int ncliques;
2279  int currentgubconsidx;
2280  int newgubconsidx;
2281  int cliqueidx;
2282  int nvars;
2283  int i;
2284 
2285  assert(scip != NULL);
2286  assert(gubset != NULL);
2287  assert(vars != NULL);
2288 
2289  nvars = gubset->nvars;
2290  assert(nvars >= 0);
2291 
2292  /* allocate temporary memory for clique partition */
2293  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2294 
2295  /* compute sophisticated clique partition */
2296  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2297 
2298  /* allocate temporary memory for GUB set data structure */
2299  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2300 
2301  /* translate GUB partition into GUB set data structure */
2302  for( i = 0; i < ncliques; i++ )
2303  {
2304  /* initialize first variable for every GUB */
2305  gubfirstvar[i] = -1;
2306  }
2307  /* move every knapsack variable into GUB defined by clique partition */
2308  for( i = 0; i < nvars; i++ )
2309  {
2310  assert(cliquepartition[i] >= 0);
2311 
2312  cliqueidx = cliquepartition[i];
2313  currentgubconsidx = gubset->gubconssidx[i];
2314  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2315 
2316  /* variable is first element in GUB constraint defined by clique partition */
2317  if( gubfirstvar[cliqueidx] == -1 )
2318  {
2319  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2320  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2321  */
2322  assert(gubset->gubvarsidx[i] == 0);
2323  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2324 
2325  /* remember the first variable found for the current GUB */
2326  gubfirstvar[cliqueidx] = i;
2327  }
2328  /* variable is additional element of GUB constraint defined by clique partition */
2329  else
2330  {
2331  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2332 
2333  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2334  * first variable of this GUB constraint
2335  */
2336  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2337  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2338  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2339 
2340  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2341  }
2342  }
2343 
2344 #ifdef SCIP_DEBUG
2345  /* prints GUB set data structure */
2346  GUBsetPrint(scip, gubset, vars, solvals);
2347 #endif
2348 
2349 #ifndef NDEBUG
2350  /* checks consistency of GUB set data structure */
2351  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2352 #endif
2353 
2354  /* free temporary memory */
2355  SCIPfreeBufferArray(scip, &gubfirstvar);
2356  SCIPfreeBufferArray(scip, &cliquepartition);
2357 
2358  return SCIP_OKAY;
2359 }
2360 
2361 /** 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$
2362  * 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
2363  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2364  */
2365 static
2367  SCIP* scip, /**< SCIP data structure */
2368  SCIP_VAR** vars, /**< variables in knapsack constraint */
2369  int nvars, /**< number of variables in knapsack constraint */
2370  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2371  SCIP_Longint capacity, /**< capacity of knapsack */
2372  SCIP_Real* solvals, /**< solution values of all problem variables */
2373  int* covervars, /**< pointer to store cover variables */
2374  int* noncovervars, /**< pointer to store noncover variables */
2375  int* ncovervars, /**< pointer to store number of cover variables */
2376  int* nnoncovervars, /**< pointer to store number of noncover variables */
2377  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2378  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2379  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2380  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2381  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2382  )
2383 {
2384  SCIP_Longint* transweights;
2385  SCIP_Real* transprofits;
2386  SCIP_Longint transcapacity;
2387  SCIP_Longint fixedonesweight;
2388  SCIP_Longint itemsweight;
2389  SCIP_Bool infeasible;
2390  int* fixedones;
2391  int* fixedzeros;
2392  int* items;
2393  int nfixedones;
2394  int nfixedzeros;
2395  int nitems;
2396  int j;
2397 
2398  assert(scip != NULL);
2399  assert(vars != NULL);
2400  assert(nvars > 0);
2401  assert(weights != NULL);
2402  assert(capacity >= 0);
2403  assert(solvals != NULL);
2404  assert(covervars != NULL);
2405  assert(noncovervars != NULL);
2406  assert(ncovervars != NULL);
2407  assert(nnoncovervars != NULL);
2408  assert(coverweight != NULL);
2409  assert(found != NULL);
2410  assert(ntightened != NULL);
2411  assert(fractional != NULL);
2412 
2413  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2414 
2415  /* allocates temporary memory */
2416  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2417  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2418  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2419  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2420  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2421 
2422  *found = FALSE;
2423  *ncovervars = 0;
2424  *nnoncovervars = 0;
2425  *coverweight = 0;
2426  *fractional = TRUE;
2427 
2428  /* gets the following sets
2429  * N_1 = {j in N : x*_j = 1} (fixedones),
2430  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2431  * N\(N_0 & N_1) (items),
2432  * where x*_j is the solution value of variable x_j
2433  */
2434  nfixedones = 0;
2435  nfixedzeros = 0;
2436  nitems = 0;
2437  fixedonesweight = 0;
2438  itemsweight = 0;
2439  *ntightened = 0;
2440  for( j = 0; j < nvars; j++ )
2441  {
2442  assert(SCIPvarIsBinary(vars[j]));
2443 
2444  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2445  if( weights[j] > capacity )
2446  {
2447  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2448  assert(!infeasible);
2449  (*ntightened)++;
2450  continue;
2451  }
2452 
2453  /* variable x_j has solution value one */
2454  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2455  {
2456  fixedones[nfixedones] = j;
2457  nfixedones++;
2458  fixedonesweight += weights[j];
2459  }
2460  /* variable x_j has solution value zero */
2461  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2462  {
2463  fixedzeros[nfixedzeros] = j;
2464  nfixedzeros++;
2465  }
2466  /* variable x_j has fractional solution value */
2467  else
2468  {
2469  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2470  items[nitems] = j;
2471  nitems++;
2472  itemsweight += weights[j];
2473  }
2474  }
2475  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2476 
2477  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2478  * the separation routine
2479  */
2480  assert(nitems >= 0);
2481  if( nitems == 0 )
2482  {
2483  *fractional = FALSE;
2484  goto TERMINATE;
2485  }
2486  assert(*fractional);
2487 
2488  /* transforms the traditional separation problem (under consideration of the following fixing:
2489  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2490  *
2491  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2492  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2493  * z_j in {0,1}, j in N\(N_0 & N_1)
2494  *
2495  * to a knapsack problem in maximization form by complementing the variables
2496  *
2497  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2498  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2499  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2500  * z_j in {0,1}, j in N\(N_0 & N_1)
2501  */
2502 
2503  /* gets weight and profit of variables in transformed knapsack problem */
2504  for( j = 0; j < nitems; j++ )
2505  {
2506  transweights[j] = weights[items[j]];
2507  transprofits[j] = 1.0 - solvals[items[j]];
2508  }
2509  /* gets capacity of transformed knapsack problem */
2510  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2511 
2512  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2513  * (when variables fixed to zero are not used)
2514  */
2515  if( transcapacity < 0 )
2516  {
2517  assert(!(*found));
2518  goto TERMINATE;
2519  }
2520 
2521  if( modtransused )
2522  {
2523  /* transforms the modified separation problem (under consideration of the following fixing:
2524  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2525  *
2526  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2527  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2528  * z_j in {0,1}, j in N\(N_0 & N_1)
2529  *
2530  * to a knapsack problem in maximization form by complementing the variables
2531  *
2532  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2533  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2534  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2535  * z_j in {0,1}, j in N\(N_0 & N_1)
2536  */
2537 
2538  /* gets weight and profit of variables in modified transformed knapsack problem */
2539  for( j = 0; j < nitems; j++ )
2540  {
2541  transprofits[j] *= weights[items[j]];
2542  assert(SCIPisFeasPositive(scip, transprofits[j]));
2543  }
2544  }
2545 
2546  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2547  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2548  * let z* be the solution, then
2549  * j in C, if z*_j = 0 and
2550  * i in N\C, if z*_j = 1.
2551  */
2552  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2553  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2554  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2555 
2556  /* constructs cover C (sum_{j in C} a_j > a_0) */
2557  for( j = 0; j < *ncovervars; j++ )
2558  {
2559  (*coverweight) += weights[covervars[j]];
2560  }
2561 
2562  /* adds all variables from N_1 to C */
2563  for( j = 0; j < nfixedones; j++ )
2564  {
2565  covervars[*ncovervars] = fixedones[j];
2566  (*ncovervars)++;
2567  (*coverweight) += weights[fixedones[j]];
2568  }
2569 
2570  /* adds all variables from N_0 to N\C */
2571  for( j = 0; j < nfixedzeros; j++ )
2572  {
2573  noncovervars[*nnoncovervars] = fixedzeros[j];
2574  (*nnoncovervars)++;
2575  }
2576  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2577  assert((*coverweight) > capacity);
2578  *found = TRUE;
2579 
2580  TERMINATE:
2581  /* frees temporary memory */
2582  SCIPfreeBufferArray(scip, &items);
2583  SCIPfreeBufferArray(scip, &fixedzeros);
2584  SCIPfreeBufferArray(scip, &fixedones);
2585  SCIPfreeBufferArray(scip, &transprofits);
2586  SCIPfreeBufferArray(scip, &transweights);
2587 
2588  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2589 
2590  return SCIP_OKAY;
2591 }
2592 
2593 #ifndef NDEBUG
2594 /** checks if minweightidx is set correctly
2595  */
2596 static
2598  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2599  SCIP_Longint capacity, /**< capacity of knapsack */
2600  int* covervars, /**< pointer to store cover variables */
2601  int ncovervars, /**< pointer to store number of cover variables */
2602  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2603  int minweightidx, /**< index of variable in cover variables with minimum weight */
2604  int j /**< current index in cover variables */
2605  )
2606 {
2607  SCIP_Longint minweight;
2608  int i;
2609 
2610  assert(weights != NULL);
2611  assert(covervars != NULL);
2612  assert(ncovervars > 0);
2613 
2614  minweight = weights[covervars[minweightidx]];
2615 
2616  /* checks if all cover variables before index j have weight greater than minweight */
2617  for( i = 0; i < j; i++ )
2618  {
2619  assert(weights[covervars[i]] > minweight);
2620  if( weights[covervars[i]] <= minweight )
2621  return FALSE;
2622  }
2623 
2624  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2625  for( i = 0; i < j; i++ )
2626  {
2627  assert(coverweight - weights[covervars[i]] <= capacity);
2628  if( coverweight - weights[covervars[i]] > capacity )
2629  return FALSE;
2630  }
2631  return TRUE;
2632 }
2633 #endif
2634 
2635 
2636 /** 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$,
2637  * 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$
2638  */
2639 static
2641  SCIP* scip, /**< SCIP data structure */
2642  SCIP_Real* solvals, /**< solution values of all problem variables */
2643  int* covervars, /**< cover variables */
2644  int ncovervars, /**< number of cover variables */
2645  int* varsC1, /**< pointer to store variables in C1 */
2646  int* varsC2, /**< pointer to store variables in C2 */
2647  int* nvarsC1, /**< pointer to store number of variables in C1 */
2648  int* nvarsC2 /**< pointer to store number of variables in C2 */
2649  )
2650 {
2651  int j;
2652 
2653  assert(scip != NULL);
2654  assert(ncovervars >= 0);
2655  assert(solvals != NULL);
2656  assert(covervars != NULL);
2657  assert(varsC1 != NULL);
2658  assert(varsC2 != NULL);
2659  assert(nvarsC1 != NULL);
2660  assert(nvarsC2 != NULL);
2661 
2662  *nvarsC1 = 0;
2663  *nvarsC2 = 0;
2664  for( j = 0; j < ncovervars; j++ )
2665  {
2666  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2667 
2668  /* variable has solution value one */
2669  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2670  {
2671  varsC2[*nvarsC2] = covervars[j];
2672  (*nvarsC2)++;
2673  }
2674  /* variable has solution value less than one */
2675  else
2676  {
2677  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2678  varsC1[*nvarsC1] = covervars[j];
2679  (*nvarsC1)++;
2680  }
2681  }
2682  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2683 }
2684 
2685 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2686  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2687  */
2688 static
2690  SCIP* scip, /**< SCIP data structure */
2691  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2692  int* varsC1, /**< pointer to store variables in C1 */
2693  int* varsC2, /**< pointer to store variables in C2 */
2694  int* nvarsC1, /**< pointer to store number of variables in C1 */
2695  int* nvarsC2 /**< pointer to store number of variables in C2 */
2696  )
2698  SCIP_Real* sortkeysC2;
2699  int j;
2700 
2701  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2702  assert(*nvarsC2 > 0);
2703 
2704  /* allocates temporary memory */
2705  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2706 
2707  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2708  for( j = 0; j < *nvarsC2; j++ )
2709  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2710  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2711 
2712  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2713  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2714  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2715  {
2716  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2717  (*nvarsC1)++;
2718  (*nvarsC2)--;
2719  }
2720 
2721  /* frees temporary memory */
2722  SCIPfreeBufferArray(scip, &sortkeysC2);
2723 
2724  return SCIP_OKAY;
2725 }
2726 
2727 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2728 static
2730  SCIP* scip, /**< SCIP data structure */
2731  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2732  int* varsC1, /**< pointer to store variables in C1 */
2733  int* varsC2, /**< pointer to store variables in C2 */
2734  int* nvarsC1, /**< pointer to store number of variables in C1 */
2735  int* nvarsC2 /**< pointer to store number of variables in C2 */
2736  )
2738  SCIP_Real* sortkeysC2;
2739  int j;
2740 
2741  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2742  assert(*nvarsC2 > 0);
2743 
2744  /* allocates temporary memory */
2745  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2746 
2747  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2748  for( j = 0; j < *nvarsC2; j++ )
2749  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2750  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2751 
2752  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2753  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2754  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2755  (*nvarsC1)++;
2756  (*nvarsC2)--;
2757 
2758  /* frees temporary memory */
2759  SCIPfreeBufferArray(scip, &sortkeysC2);
2760 
2761  return SCIP_OKAY;
2762 }
2763 
2764 
2765 /** 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$
2766  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2767  * \f$F = (N \setminus C) \setminus F\f$
2768  */
2769 static
2771  SCIP* scip, /**< SCIP data structure */
2772  SCIP_Real* solvals, /**< solution values of all problem variables */
2773  int* noncovervars, /**< noncover variables */
2774  int nnoncovervars, /**< number of noncover variables */
2775  int* varsF, /**< pointer to store variables in F */
2776  int* varsR, /**< pointer to store variables in R */
2777  int* nvarsF, /**< pointer to store number of variables in F */
2778  int* nvarsR /**< pointer to store number of variables in R */
2779  )
2780 {
2781  int j;
2782 
2783  assert(scip != NULL);
2784  assert(nnoncovervars >= 0);
2785  assert(solvals != NULL);
2786  assert(noncovervars != NULL);
2787  assert(varsF != NULL);
2788  assert(varsR != NULL);
2789  assert(nvarsF != NULL);
2790  assert(nvarsR != NULL);
2791 
2792  *nvarsF = 0;
2793  *nvarsR = 0;
2794 
2795  for( j = 0; j < nnoncovervars; j++ )
2796  {
2797  /* variable has solution value zero */
2798  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2799  {
2800  varsR[*nvarsR] = noncovervars[j];
2801  (*nvarsR)++;
2802  }
2803  /* variable has solution value greater than zero */
2804  else
2805  {
2806  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2807  varsF[*nvarsF] = noncovervars[j];
2808  (*nvarsF)++;
2809  }
2810  }
2811  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2812 }
2813 
2814 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2815  * lifting procedure
2816  */
2817 static
2819  SCIP* scip, /**< SCIP data structure */
2820  SCIP_Real* solvals, /**< solution values of all problem variables */
2821  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2822  int* varsF, /**< pointer to store variables in F */
2823  int* varsC2, /**< pointer to store variables in C2 */
2824  int* varsR, /**< pointer to store variables in R */
2825  int nvarsF, /**< number of variables in F */
2826  int nvarsC2, /**< number of variables in C2 */
2827  int nvarsR /**< number of variables in R */
2828  )
2829 {
2830  SORTKEYPAIR** sortkeypairsF;
2831  SORTKEYPAIR* sortkeypairsFstore;
2832  SCIP_Real* sortkeysC2;
2833  SCIP_Real* sortkeysR;
2834  int j;
2835 
2836  assert(scip != NULL);
2837  assert(solvals != NULL);
2838  assert(weights != NULL);
2839  assert(varsF != NULL);
2840  assert(varsC2 != NULL);
2841  assert(varsR != NULL);
2842  assert(nvarsF >= 0);
2843  assert(nvarsC2 >= 0);
2844  assert(nvarsR >= 0);
2845 
2846  /* allocates temporary memory */
2847  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2848  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2849  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2850  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2851 
2852  /* gets sorting key for variables in F corresponding to the following lifting sequence
2853  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2854  * x*_1 >= x*_2 >= ... >= x*_|F|
2855  * in case of equality uses
2856  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2857  */
2858  for( j = 0; j < nvarsF; j++ )
2859  {
2860  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2861  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2862  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2863  }
2864 
2865  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2866  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2867  */
2868  for( j = 0; j < nvarsC2; j++ )
2869  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2870 
2871  /* gets sorting key for variables in R corresponding to the following lifting sequence
2872  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2873  */
2874  for( j = 0; j < nvarsR; j++ )
2875  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2876 
2877  /* sorts F, C2 and R */
2878  if( nvarsF > 0 )
2879  {
2880  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2881  }
2882  if( nvarsC2 > 0 )
2883  {
2884  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2885  }
2886  if( nvarsR > 0)
2887  {
2888  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2889  }
2890 
2891  /* frees temporary memory */
2892  SCIPfreeBufferArray(scip, &sortkeysR);
2893  SCIPfreeBufferArray(scip, &sortkeysC2);
2894  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2895  SCIPfreeBufferArray(scip, &sortkeypairsF);
2896 
2897  return SCIP_OKAY;
2898 }
2899 
2900 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2901  * for the sequential GUB wise lifting procedure
2902  */
2903 static
2905  SCIP* scip, /**< SCIP data structure */
2906  SCIP_GUBSET* gubset, /**< GUB set data structure */
2907  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2908  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2909  int* varsC1, /**< variables in C1 */
2910  int* varsC2, /**< variables in C2 */
2911  int* varsF, /**< variables in F */
2912  int* varsR, /**< variables in R */
2913  int nvarsC1, /**< number of variables in C1 */
2914  int nvarsC2, /**< number of variables in C2 */
2915  int nvarsF, /**< number of variables in F */
2916  int nvarsR, /**< number of variables in R */
2917  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2918  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2919  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2920  int* gubconsGR, /**< pointer to store GUBs in GR */
2921  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2922  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2923  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2924  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2925  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2926  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2927  )
2928 {
2929 #if 0 /* not required */
2930  SORTKEYPAIR** sortkeypairsF;
2931 #endif
2932  SORTKEYPAIR** sortkeypairsGFC1;
2933  SORTKEYPAIR* sortkeypairsGFC1store;
2934  SCIP_Real* sortkeysC1;
2935  SCIP_Real* sortkeysC2;
2936  SCIP_Real* sortkeysR;
2937  int* nC1varsingubcons;
2938  int var;
2939  int gubconsidx;
2940  int varidx;
2941  int ngubconss;
2942  int ngubconsGOC1;
2943  int targetvar;
2944  int nvarsprocessed;
2945  int i;
2946  int j;
2947 
2948 #if GUBSPLITGNC1GUBS
2949  SCIP_Bool gubconswithF;
2950  int origngubconss;
2951  origngubconss = gubset->ngubconss;
2952 #endif
2953 
2954  assert(scip != NULL);
2955  assert(gubset != NULL);
2956  assert(solvals != NULL);
2957  assert(weights != NULL);
2958  assert(varsC1 != NULL);
2959  assert(varsC2 != NULL);
2960  assert(varsF != NULL);
2961  assert(varsR != NULL);
2962  assert(nvarsC1 > 0);
2963  assert(nvarsC2 >= 0);
2964  assert(nvarsF >= 0);
2965  assert(nvarsR >= 0);
2966  assert(gubconsGC1 != NULL);
2967  assert(gubconsGC2 != NULL);
2968  assert(gubconsGFC1 != NULL);
2969  assert(gubconsGR != NULL);
2970  assert(ngubconsGC1 != NULL);
2971  assert(ngubconsGC2 != NULL);
2972  assert(ngubconsGFC1 != NULL);
2973  assert(ngubconsGR != NULL);
2974  assert(maxgubvarssize != NULL);
2975 
2976  ngubconss = gubset->ngubconss;
2977  nvarsprocessed = 0;
2978  ngubconsGOC1 = 0;
2979 
2980  /* GUBs are categorized into different types according to the variables in volved
2981  * - GOC1: involves variables in C1 only -- no C2, R, F
2982  * - GNC1: involves variables in C1 and F (and R) -- no C2
2983  * - GF: involves variables in F (and R) only -- no C1, C2
2984  * - GC2: involves variables in C2 only -- no C1, R, F
2985  * - GR: involves variables in R only -- no C1, C2, F
2986  * which requires splitting GUBs in case they include variable in F and R.
2987  *
2988  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2989  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2990  * - second ordering level is
2991  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2992  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2993  * GR: non-increasing max{ a_k : k in GR_j}
2994  *
2995  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2996  * - GC1: GUBs of category GOC1 and GNC1
2997  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2998  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2999  */
3000 
3001  /* allocates temporary memory */
3002  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3003 #if 0 /* not required */
3004  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
3005 #endif
3006  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3007  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3008 
3009  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3010  * - F: non-increasing x*_j and non-increasing a_j in case of equality
3011  * - C2: non-increasing a_j
3012  * - R: non-increasing a_j
3013  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3014  */
3015 
3016  /* gets sorting key for variables in C1 corresponding to the following ordering
3017  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3018  */
3019  for( j = 0; j < nvarsC1; j++ )
3020  {
3021  /* gets sortkeys */
3022  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3023 
3024  /* update status of variable in its gub constraint */
3025  gubconsidx = gubset->gubconssidx[varsC1[j]];
3026  varidx = gubset->gubvarsidx[varsC1[j]];
3027  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3028  }
3029 
3030  /* gets sorting key for variables in F corresponding to the following ordering
3031  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3032  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3033  * and updates status of each variable in F in GUB set data structure
3034  */
3035  for( j = 0; j < nvarsF; j++ )
3036  {
3037 #if 0 /* not required */
3038  /* gets sortkeys */
3039  SCIP_CALL( SCIPallocBuffer(scip, &sortkeypairsF[j]) );
3040  sortkeypairsF[j]->key1 = solvals[varsF[j]];
3041  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
3042 #endif
3043 
3044  /* update status of variable in its gub constraint */
3045  gubconsidx = gubset->gubconssidx[varsF[j]];
3046  varidx = gubset->gubvarsidx[varsF[j]];
3047  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3048  }
3049 
3050  /* gets sorting key for variables in C2 corresponding to the following ordering
3051  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3052  * and updates status of each variable in F in GUB set data structure
3053  */
3054  for( j = 0; j < nvarsC2; j++ )
3055  {
3056  /* gets sortkeys */
3057  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3058 
3059  /* update status of variable in its gub constraint */
3060  gubconsidx = gubset->gubconssidx[varsC2[j]];
3061  varidx = gubset->gubvarsidx[varsC2[j]];
3062  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3063  }
3064 
3065  /* gets sorting key for variables in R corresponding to the following ordering
3066  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3067  * and updates status of each variable in F in GUB set data structure
3068  */
3069  for( j = 0; j < nvarsR; j++ )
3070  {
3071  /* gets sortkeys */
3072  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3073 
3074  /* update status of variable in its gub constraint */
3075  gubconsidx = gubset->gubconssidx[varsR[j]];
3076  varidx = gubset->gubvarsidx[varsR[j]];
3077  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3078  }
3079 
3080  /* sorts C1, F, C2 and R */
3081  if( nvarsC1 > 0 )
3082  {
3083  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3084  }
3085 #if 0 /* not required */
3086  if( nvarsF > 0 )
3087  {
3088  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
3089  }
3090 #endif
3091  if( nvarsC2 > 0 )
3092  {
3093  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3094  }
3095  if( nvarsR > 0)
3096  {
3097  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3098  }
3099 
3100  /* frees temporary memory */
3101  SCIPfreeBufferArray(scip, &sortkeysR);
3102  SCIPfreeBufferArray(scip, &sortkeysC2);
3103 #if 0 /* not required */
3104  for( j = nvarsF-1; j >= 0; j-- )
3105  SCIPfreeBuffer(scip, &sortkeypairsF[j]);
3106  SCIPfreeBufferArray(scip, &sortkeypairsF);
3107 #endif
3108  SCIPfreeBufferArray(scip, &sortkeysC1);
3109 
3110  /* allocate and initialize temporary memory for sorting GUB constraints */
3111  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3112  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3113  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3114  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3115  for( i = 0; i < ngubconss; i++)
3116  {
3117  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3118  sortkeypairsGFC1[i]->key1 = 0.0;
3119  sortkeypairsGFC1[i]->key2 = 0.0;
3120  }
3121  *ngubconsGC1 = 0;
3122  *ngubconsGC2 = 0;
3123  *ngubconsGFC1 = 0;
3124  *ngubconsGR = 0;
3125  *ngubconscapexceed = 0;
3126  *maxgubvarssize = 0;
3127 
3128 #ifndef NDEBUG
3129  for( i = 0; i < gubset->ngubconss; i++ )
3130  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3131 #endif
3132 
3133  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3134  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3135  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3136  * non-increasing number of variables in F, and
3137  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3138  */
3139  for( i = 0; i < nvarsC1; i++ )
3140  {
3141  int nvarsC1capexceed;
3142 
3143  nvarsC1capexceed = 0;
3144 
3145  var = varsC1[i];
3146  gubconsidx = gubset->gubconssidx[var];
3147  varidx = gubset->gubvarsidx[var];
3148 
3149  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3150  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3151 
3152  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3153  * note that variables in C1 are already sorted by non-decreasing weigth
3154  */
3155  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3156  GUBsetSwapVars(scip, gubset, var, targetvar);
3157  nC1varsingubcons[gubconsidx]++;
3158 
3159  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3160  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3161  {
3162  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3163  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3164  continue;
3165  }
3166 
3167  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3168  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3169  */
3170 #if GUBSPLITGNC1GUBS
3171  gubconswithF = FALSE;
3172 #endif
3173  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3174  {
3175  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3176 
3177  /* C1-variable: update number of C1/capacity exceeding variables */
3178  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3179  {
3180  nvarsC1capexceed++;
3181  nvarsprocessed++;
3182  }
3183  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3184  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3185  {
3186 #if GUBSPLITGNC1GUBS
3187  gubconswithF = TRUE;
3188 #endif
3189  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3190 
3191  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3192  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3193  }
3194  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3195  {
3196  nvarsC1capexceed++;
3197  }
3198  else
3199  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3200  }
3201 
3202  /* update set of GC1 GUBs */
3203  gubconsGC1[*ngubconsGC1] = gubconsidx;
3204  (*ngubconsGC1)++;
3205 
3206  /* update maximum size of all GUB constraints */
3207  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3208  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3209 
3210  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3211  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3212  {
3213  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3214  ngubconsGOC1++;
3215  }
3216  else
3217  {
3218 #if GUBSPLITGNC1GUBS
3219  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3220  if( !gubconswithF )
3221  {
3222  GUBVARSTATUS movevarstatus;
3223 
3224  assert(gubset->ngubconss < gubset->nvars);
3225 
3226  /* create a new GUB for GR part of splitting */
3227  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3228  gubset->ngubconss++;
3229  ngubconss = gubset->ngubconss;
3230 
3231  /* fill GR with R variables in current GUB */
3232  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3233  {
3234  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3235  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3236  {
3237  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3238  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3239  gubconsidx, ngubconss-1) );
3240  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3241  movevarstatus;
3242  }
3243  }
3244 
3245  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3246  ngubconsGOC1++;
3247 
3248  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3249  gubconsGR[*ngubconsGR] = ngubconss-1;
3250  (*ngubconsGR)++;
3251  }
3252  /* variables in C1, F, and maybe R: GNC1 GUB */
3253  else
3254  {
3255  assert(gubconswithF);
3256 
3257  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3258  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3259  (*ngubconsGFC1)++;
3260  }
3261 #else
3262  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3263  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3264  (*ngubconsGFC1)++;
3265 #endif
3266  }
3267  }
3268 
3269  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3270  * are already sorted correctly
3271  */
3272  for( i = 0; i < nvarsC2; i++ )
3273  {
3274  var = varsC2[i];
3275  gubconsidx = gubset->gubconssidx[var];
3276  varidx = gubset->gubvarsidx[var];
3277 
3278  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3279  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3280  assert(varidx == 0);
3281  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3282  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3283 
3284  /* set status of GC2 GUB */
3285  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3286 
3287  /* update group of GC2 GUBs */
3288  gubconsGC2[*ngubconsGC2] = gubconsidx;
3289  (*ngubconsGC2)++;
3290 
3291  /* update maximum size of all GUB constraints */
3292  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3293  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3294 
3295  nvarsprocessed++;
3296  }
3297 
3298  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3299  * non-increasing number of variables in F, and
3300  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3301  */
3302  for( i = 0; i < nvarsF; i++ )
3303  {
3304  var = varsF[i];
3305  gubconsidx = gubset->gubconssidx[var];
3306  varidx = gubset->gubvarsidx[var];
3307 
3308  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3309  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3310 
3311  nvarsprocessed++;
3312 
3313  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3314  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3315  {
3316  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3317  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3318  continue;
3319  }
3320 
3321  /* set status of GF GUB */
3322  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3323 
3324  /* update sorting key of corresponding GFC1 GUB */
3325  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3326  {
3327  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3328  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3329 
3330  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3331  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3332  {
3333  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3334 
3335  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3336  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3337  }
3338  }
3339 
3340  /* update set of GFC1 GUBs */
3341  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3342  (*ngubconsGFC1)++;
3343 
3344  /* update maximum size of all GUB constraints */
3345  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3346  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3347  }
3348 
3349  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3350  * correctly
3351  */
3352  for( i = 0; i < nvarsR; i++ )
3353  {
3354  var = varsR[i];
3355  gubconsidx = gubset->gubconssidx[var];
3356  varidx = gubset->gubvarsidx[var];
3357 
3358  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3359  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3360 
3361  nvarsprocessed++;
3362 
3363  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3364  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3365  {
3366  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3367  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3368  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3369  continue;
3370  }
3371 
3372  /* set status of GR GUB */
3373  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3374 
3375  /* update set of GR GUBs */
3376  gubconsGR[*ngubconsGR] = gubconsidx;
3377  (*ngubconsGR)++;
3378 
3379  /* update maximum size of all GUB constraints */
3380  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3381  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3382  }
3383  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3384 
3385  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3386  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3387  assert(*ngubconscapexceed >= 0);
3388 #ifndef NDEBUG
3389  {
3390  int check;
3391 
3392  check = 0;
3393 
3394  /* remaining not handled GUBs should only contain capacity exceeding variables */
3395  for( i = 0; i < ngubconss; i++ )
3396  {
3397  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3398  check++;
3399  }
3400  assert(check == *ngubconscapexceed);
3401  }
3402 #endif
3403 
3404  /* sort GFCI GUBs according to computed sorting keys */
3405  if( (*ngubconsGFC1) > 0 )
3406  {
3407  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3408  }
3409 
3410  /* free temporary memory */
3411 #if GUBSPLITGNC1GUBS
3412  ngubconss = origngubconss;
3413 #endif
3414  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3415  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3416  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3417 
3418  return SCIP_OKAY;
3419 }
3420 
3421 /** enlarges minweight table to at least the given length */
3422 static
3424  SCIP* scip, /**< SCIP data structure */
3425  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3426  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3427  int* minweightssize, /**< pointer to current size of minweights table */
3428  int newlen /**< new length of minweights table */
3429  )
3430 {
3431  int j;
3432 
3433  assert(minweightsptr != NULL);
3434  assert(*minweightsptr != NULL);
3435  assert(minweightslen != NULL);
3436  assert(*minweightslen >= 0);
3437  assert(minweightssize != NULL);
3438  assert(*minweightssize >= 0);
3439 
3440  if( newlen > *minweightssize )
3441  {
3442  int newsize;
3443 
3444  /* reallocate table memory */
3445  newsize = SCIPcalcMemGrowSize(scip, newlen);
3446  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3447  *minweightssize = newsize;
3448  }
3449  assert(newlen <= *minweightssize);
3450 
3451  /* initialize new elements */
3452  for( j = *minweightslen; j < newlen; ++j )
3453  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3454  *minweightslen = newlen;
3455 
3456  return SCIP_OKAY;
3457 }
3458 
3459 /** lifts given inequality
3460  * sum_{j in M_1} x_j <= alpha_0
3461  * valid for
3462  * 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 }
3463  * to a valid inequality
3464  * 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
3465  * <= alpha_0 + sum_{j in M_2} alpha_j
3466  * for
3467  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3468  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3469  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3470  * extended weight inequalities.
3471  */
3472 static
3474  SCIP* scip, /**< SCIP data structure */
3475  SCIP_VAR** vars, /**< variables in knapsack constraint */
3476  int nvars, /**< number of variables in knapsack constraint */
3477  int ntightened, /**< number of variables with tightened upper bound */
3478  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3479  SCIP_Longint capacity, /**< capacity of knapsack */
3480  SCIP_Real* solvals, /**< solution values of all problem variables */
3481  int* varsM1, /**< variables in M_1 */
3482  int* varsM2, /**< variables in M_2 */
3483  int* varsF, /**< variables in F */
3484  int* varsR, /**< variables in R */
3485  int nvarsM1, /**< number of variables in M_1 */
3486  int nvarsM2, /**< number of variables in M_2 */
3487  int nvarsF, /**< number of variables in F */
3488  int nvarsR, /**< number of variables in R */
3489  int alpha0, /**< rights hand side of given valid inequality */
3490  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3491  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3492  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3493  )
3494 {
3495  SCIP_Longint* minweights;
3496  SCIP_Real* sortkeys;
3497  SCIP_Longint fixedonesweight;
3498  int minweightssize;
3499  int minweightslen;
3500  int j;
3501  int w;
3502 
3503  assert(scip != NULL);
3504  assert(vars != NULL);
3505  assert(nvars >= 0);
3506  assert(weights != NULL);
3507  assert(capacity >= 0);
3508  assert(solvals != NULL);
3509  assert(varsM1 != NULL);
3510  assert(varsM2 != NULL);
3511  assert(varsF != NULL);
3512  assert(varsR != NULL);
3513  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3514  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3515  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3516  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3517  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3518  assert(alpha0 >= 0);
3519  assert(liftcoefs != NULL);
3520  assert(cutact != NULL);
3521  assert(liftrhs != NULL);
3522 
3523  /* allocates temporary memory */
3524  minweightssize = nvarsM1 + 1;
3525  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3526  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3527 
3528  /* initializes data structures */
3529  BMSclearMemoryArray(liftcoefs, nvars);
3530  *cutact = 0.0;
3531 
3532  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3533  * and calculates activity of the current valid inequality
3534  */
3535  for( j = 0; j < nvarsM1; j++ )
3536  {
3537  assert(liftcoefs[varsM1[j]] == 0);
3538  liftcoefs[varsM1[j]] = 1;
3539  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3540  (*cutact) += solvals[varsM1[j]];
3541  }
3542 
3543  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3544 
3545  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3546  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3547  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3548  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3549  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3550  */
3551  minweights[0] = 0;
3552  for( w = 1; w <= nvarsM1; w++ )
3553  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3554  minweightslen = nvarsM1 + 1;
3555 
3556  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3557  fixedonesweight = 0;
3558  for( j = 0; j < nvarsM2; j++ )
3559  fixedonesweight += weights[varsM2[j]];
3560  assert(fixedonesweight >= 0);
3561 
3562  /* initializes right hand side of lifted valid inequality */
3563  *liftrhs = alpha0;
3564 
3565  /* sequentially up-lifts all variables in F: */
3566  for( j = 0; j < nvarsF; j++ )
3567  {
3568  SCIP_Longint weight;
3569  int liftvar;
3570  int liftcoef;
3571  int z;
3572 
3573  liftvar = varsF[j];
3574  weight = weights[liftvar];
3575  assert(liftvar >= 0 && liftvar < nvars);
3576  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3577  assert(weight > 0);
3578 
3579  /* knapsack problem is infeasible:
3580  * sets z = 0
3581  */
3582  if( capacity - fixedonesweight - weight < 0 )
3583  {
3584  z = 0;
3585  }
3586  /* knapsack problem is feasible:
3587  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3588  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3589  */
3590  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3591  {
3592  z = *liftrhs;
3593  }
3594  /* knapsack problem is feasible:
3595  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3596  */
3597  else
3598  {
3599  int left;
3600  int right;
3601  int middle;
3602 
3603  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3604  left = 0;
3605  right = (*liftrhs) + 1;
3606  while( left < right - 1 )
3607  {
3608  middle = (left + right) / 2;
3609  assert(0 <= middle && middle < minweightslen);
3610  if( minweights[middle] <= capacity - fixedonesweight - weight )
3611  left = middle;
3612  else
3613  right = middle;
3614  }
3615  assert(left == right - 1);
3616  assert(0 <= left && left < minweightslen);
3617  assert(minweights[left] <= capacity - fixedonesweight - weight );
3618  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3619 
3620  /* now z = left */
3621  z = left;
3622  assert(z <= *liftrhs);
3623  }
3624 
3625  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3626  liftcoef = (*liftrhs) - z;
3627  liftcoefs[liftvar] = liftcoef;
3628  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3629 
3630  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3631  if( liftcoef == 0 )
3632  continue;
3633 
3634  /* updates activity of current valid inequality */
3635  (*cutact) += liftcoef * solvals[liftvar];
3636 
3637  /* enlarges current minweight table:
3638  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3639  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3640  * and sets minweights_i[w] = infinity for
3641  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3642  */
3643  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3644 
3645  /* updates minweight table: minweight_i+1[w] =
3646  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3647  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3648  */
3649  for( w = minweightslen - 1; w >= 0; w-- )
3650  {
3651  SCIP_Longint min;
3652  if( w < liftcoef )
3653  {
3654  min = MIN(minweights[w], weight);
3655  minweights[w] = min;
3656  }
3657  else
3658  {
3659  assert(w >= liftcoef);
3660  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3661  minweights[w] = min;
3662  }
3663  }
3664  }
3665  assert(minweights[0] == 0);
3666 
3667  /* sequentially down-lifts all variables in M_2: */
3668  for( j = 0; j < nvarsM2; j++ )
3669  {
3670  SCIP_Longint weight;
3671  int liftvar;
3672  int liftcoef;
3673  int left;
3674  int right;
3675  int middle;
3676  int z;
3677 
3678  liftvar = varsM2[j];
3679  weight = weights[liftvar];
3680  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3681  assert(liftvar >= 0 && liftvar < nvars);
3682  assert(weight > 0);
3683 
3684  /* uses binary search to find
3685  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3686  */
3687  left = 0;
3688  right = minweightslen;
3689  while( left < right - 1 )
3690  {
3691  middle = (left + right) / 2;
3692  assert(0 <= middle && middle < minweightslen);
3693  if( minweights[middle] <= capacity - fixedonesweight + weight )
3694  left = middle;
3695  else
3696  right = middle;
3697  }
3698  assert(left == right - 1);
3699  assert(0 <= left && left < minweightslen);
3700  assert(minweights[left] <= capacity - fixedonesweight + weight );
3701  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3702 
3703  /* now z = left */
3704  z = left;
3705  assert(z >= *liftrhs);
3706 
3707  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3708  liftcoef = z - (*liftrhs);
3709  liftcoefs[liftvar] = liftcoef;
3710  assert(liftcoef >= 0);
3711 
3712  /* updates sum of weights of variables fixed to one */
3713  fixedonesweight -= weight;
3714 
3715  /* updates right-hand side of current valid inequality */
3716  (*liftrhs) += liftcoef;
3717  assert(*liftrhs >= alpha0);
3718 
3719  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3720  if( liftcoef == 0 )
3721  continue;
3722 
3723  /* updates activity of current valid inequality */
3724  (*cutact) += liftcoef * solvals[liftvar];
3725 
3726  /* enlarges current minweight table:
3727  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3728  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3729  * and sets minweights_i[w] = infinity for
3730  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3731  */
3732  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3733 
3734  /* updates minweight table: minweight_i+1[w] =
3735  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3736  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3737  */
3738  for( w = minweightslen - 1; w >= 0; w-- )
3739  {
3740  SCIP_Longint min;
3741  if( w < liftcoef )
3742  {
3743  min = MIN(minweights[w], weight);
3744  minweights[w] = min;
3745  }
3746  else
3747  {
3748  assert(w >= liftcoef);
3749  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3750  minweights[w] = min;
3751  }
3752  }
3753  }
3754  assert(fixedonesweight == 0);
3755  assert(*liftrhs >= alpha0);
3756 
3757  /* sequentially up-lifts all variables in R: */
3758  for( j = 0; j < nvarsR; j++ )
3759  {
3760  SCIP_Longint weight;
3761  int liftvar;
3762  int liftcoef;
3763  int z;
3764 
3765  liftvar = varsR[j];
3766  weight = weights[liftvar];
3767  assert(liftvar >= 0 && liftvar < nvars);
3768  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3769  assert(weight > 0);
3770  assert(capacity - weight >= 0);
3771  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3772 
3773  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3774  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3775  */
3776  if( minweights[*liftrhs] <= capacity - weight )
3777  {
3778  z = *liftrhs;
3779  }
3780  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3781  */
3782  else
3783  {
3784  int left;
3785  int right;
3786  int middle;
3787 
3788  left = 0;
3789  right = (*liftrhs) + 1;
3790  while( left < right - 1)
3791  {
3792  middle = (left + right) / 2;
3793  assert(0 <= middle && middle < minweightslen);
3794  if( minweights[middle] <= capacity - weight )
3795  left = middle;
3796  else
3797  right = middle;
3798  }
3799  assert(left == right - 1);
3800  assert(0 <= left && left < minweightslen);
3801  assert(minweights[left] <= capacity - weight );
3802  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3803 
3804  /* now z = left */
3805  z = left;
3806  assert(z <= *liftrhs);
3807  }
3808 
3809  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3810  liftcoef = (*liftrhs) - z;
3811  liftcoefs[liftvar] = liftcoef;
3812  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3813 
3814  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3815  if( liftcoef == 0 )
3816  continue;
3817 
3818  /* updates activity of current valid inequality */
3819  (*cutact) += liftcoef * solvals[liftvar];
3820 
3821  /* updates minweight table: minweight_i+1[w] =
3822  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3823  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3824  */
3825  for( w = *liftrhs; w >= 0; w-- )
3826  {
3827  SCIP_Longint min;
3828  if( w < liftcoef )
3829  {
3830  min = MIN(minweights[w], weight);
3831  minweights[w] = min;
3832  }
3833  else
3834  {
3835  assert(w >= liftcoef);
3836  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3837  minweights[w] = min;
3838  }
3839  }
3840  }
3841 
3842  /* frees temporary memory */
3843  SCIPfreeBufferArray(scip, &sortkeys);
3844  SCIPfreeBufferArray(scip, &minweights);
3845 
3846  return SCIP_OKAY;
3847 }
3848 
3849 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3850 static
3852  SCIP_Longint val1, /**< first value to add */
3853  SCIP_Longint val2 /**< second value to add */
3854  )
3855 {
3856  assert(val1 >= 0);
3857  assert(val2 >= 0);
3858 
3859  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3860  return SCIP_LONGINT_MAX;
3861  else
3862  {
3863  assert(val1 <= SCIP_LONGINT_MAX - val2);
3864  return (val1 + val2);
3865  }
3866 }
3867 
3868 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3869 static
3871  SCIP_Longint* minweights, /**< minweight table to compute */
3872  SCIP_Longint* finished, /**< given finished table */
3873  SCIP_Longint* unfinished, /**< given unfinished table */
3874  int minweightslen /**< length of minweight, finished, and unfinished tables */
3875  )
3876 {
3877  int w1;
3878  int w2;
3879 
3880  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3881  * note that finished and unfished arrays sorted by non-decreasing weight
3882  */
3883 
3884  /* initialize minweight with w2 = 0 */
3885  w2 = 0;
3886  assert(unfinished[w2] == 0);
3887  for( w1 = 0; w1 < minweightslen; w1++ )
3888  minweights[w1] = finished[w1];
3889 
3890  /* consider w2 = 1, ..., minweightslen-1 */
3891  for( w2 = 1; w2 < minweightslen; w2++ )
3892  {
3893  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3894  break;
3895 
3896  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3897  {
3898  SCIP_Longint temp;
3899 
3900  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3901  if( temp <= minweights[w1+w2] )
3902  minweights[w1+w2] = temp;
3903  }
3904  }
3905 }
3906 
3907 /** lifts given inequality
3908  * sum_{j in C_1} x_j <= alpha_0
3909  * valid for
3910  * 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;
3911  * sum_{j in Q_i} x_j <= 1, forall i in I }
3912  * to a valid inequality
3913  * 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
3914  * <= alpha_0 + sum_{j in C_2} alpha_j
3915  * for
3916  * 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 };
3917  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3918  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3919  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3920  */
3921 static
3923  SCIP* scip, /**< SCIP data structure */
3924  SCIP_GUBSET* gubset, /**< GUB set data structure */
3925  SCIP_VAR** vars, /**< variables in knapsack constraint */
3926  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3927  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3928  SCIP_Longint capacity, /**< capacity of knapsack */
3929  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3930  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3931  int* gubconsGC2, /**< GUBs in GC2 */
3932  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3933  int* gubconsGR, /**< GUBs in GR */
3934  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3935  int ngubconsGC2, /**< number of GUBs in GC2 */
3936  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3937  int ngubconsGR, /**< number of GUBs in GR */
3938  int alpha0, /**< rights hand side of given valid inequality */
3939  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3940  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3941  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3942  int maxgubvarssize /**< maximal size of GUB constraints */
3943  )
3944 {
3945  SCIP_Longint* minweights;
3946  SCIP_Longint* finished;
3947  SCIP_Longint* unfinished;
3948  int* gubconsGOC1;
3949  int* gubconsGNC1;
3950  int* liftgubvars;
3951  SCIP_Longint fixedonesweight;
3952  SCIP_Longint weight;
3953  SCIP_Longint weightdiff1;
3954  SCIP_Longint weightdiff2;
3955  SCIP_Longint min;
3956  int minweightssize;
3957  int minweightslen;
3958  int nvars;
3959  int varidx;
3960  int liftgubconsidx;
3961  int liftvar;
3962  int sumliftcoef;
3963  int liftcoef;
3964  int ngubconsGOC1;
3965  int ngubconsGNC1;
3966  int left;
3967  int right;
3968  int middle;
3969  int nliftgubvars;
3970  int tmplen;
3971  int tmpsize;
3972  int j;
3973  int k;
3974  int w;
3975  int z;
3976 #ifndef NDEBUG
3977  int ngubconss;
3978  int nliftgubC1;
3979 
3980  assert(gubset != NULL);
3981  ngubconss = gubset->ngubconss;
3982 #else
3983  assert(gubset != NULL);
3984 #endif
3985 
3986  nvars = gubset->nvars;
3987 
3988  assert(scip != NULL);
3989  assert(vars != NULL);
3990  assert(nvars >= 0);
3991  assert(weights != NULL);
3992  assert(capacity >= 0);
3993  assert(solvals != NULL);
3994  assert(gubconsGC1 != NULL);
3995  assert(gubconsGC2 != NULL);
3996  assert(gubconsGFC1 != NULL);
3997  assert(gubconsGR != NULL);
3998  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3999  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4000  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4001  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4002  assert(alpha0 >= 0);
4003  assert(liftcoefs != NULL);
4004  assert(cutact != NULL);
4005  assert(liftrhs != NULL);
4006 
4007  minweightssize = ngubconsGC1+1;
4008 
4009  /* allocates temporary memory */
4010  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4011  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4012  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4013  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4014  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4015  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4016 
4017  /* initializes data structures */
4018  BMSclearMemoryArray(liftcoefs, nvars);
4019  *cutact = 0.0;
4020 
4021  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4022  * valid inequality
4023  */
4024  ngubconsGOC1 = 0;
4025  ngubconsGNC1 = 0;
4026  for( j = 0; j < ngubconsGC1; j++ )
4027  {
4028  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4029  {
4030  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4031  ngubconsGOC1++;
4032  }
4033  else
4034  {
4035  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4036  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4037  ngubconsGNC1++;
4038  }
4039  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4040  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4041  {
4042  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4043  assert(varidx >= 0 && varidx < nvars);
4044  assert(liftcoefs[varidx] == 0);
4045 
4046  liftcoefs[varidx] = 1;
4047  (*cutact) += solvals[varidx];
4048  }
4049  assert(k >= 1);
4050  }
4051  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4052  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4053 
4054  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4055  * - finished_i[w] =
4056  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4057  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4058  * sum_{j in Q_k} x_j <= 1
4059  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4060  * - unfinished_i[w] =
4061  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4062  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4063  * sum_{j in Q_k} x_j <= 1
4064  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4065  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4066  */
4067 
4068  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4069  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4070  * 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
4071  * comes from the first variable in the GUB
4072  */
4073  assert(ngubconsGOC1 <= ngubconsGC1);
4074  finished[0] = 0;
4075  for( w = 1; w <= ngubconsGOC1; w++ )
4076  {
4077  liftgubconsidx = gubconsGOC1[w-1];
4078 
4079  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4080  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4081 
4082  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4083 
4084  assert(varidx >= 0 && varidx < nvars);
4085  assert(liftcoefs[varidx] == 1);
4086 
4087  min = weights[varidx];
4088  finished[w] = finished[w-1] + min;
4089 
4090 #ifndef NDEBUG
4091  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4092  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4093  {
4094  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4095  assert(varidx >= 0 && varidx < nvars);
4096  assert(liftcoefs[varidx] == 1);
4097  assert(weights[varidx] >= min);
4098  }
4099 #endif
4100  }
4101  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4102  finished[w] = SCIP_LONGINT_MAX;
4103 
4104  /* initialize unfinished table; note that variables in GNC1 GUBs
4105  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4106  * 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
4107  * comes from the first variable in the GUB
4108  */
4109  assert(ngubconsGNC1 <= ngubconsGC1);
4110  unfinished[0] = 0;
4111  for( w = 1; w <= ngubconsGNC1; w++ )
4112  {
4113  liftgubconsidx = gubconsGNC1[w-1];
4114 
4115  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4116  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4117 
4118  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4119 
4120  assert(varidx >= 0 && varidx < nvars);
4121  assert(liftcoefs[varidx] == 1);
4122 
4123  min = weights[varidx];
4124  unfinished[w] = unfinished[w-1] + min;
4125 
4126 #ifndef NDEBUG
4127  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4128  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4129  {
4130  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4131  assert(varidx >= 0 && varidx < nvars);
4132  assert(liftcoefs[varidx] == 1);
4133  assert(weights[varidx] >= min );
4134  }
4135 #endif
4136  }
4137  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4138  unfinished[w] = SCIP_LONGINT_MAX;
4139 
4140  /* initialize minweights table; note that variables in GC1 GUBs
4141  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4142  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4143  * consuming) because is it has to be build using weights from C1 only.
4144  */
4145  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4146  minweights[0] = 0;
4147  for( w = 1; w <= ngubconsGC1; w++ )
4148  {
4149  liftgubconsidx = gubconsGC1[w-1];
4150 
4151  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4152  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4153  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4154 
4155  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4156 
4157  assert(varidx >= 0 && varidx < nvars);
4158  assert(liftcoefs[varidx] == 1);
4159 
4160  min = weights[varidx];
4161  minweights[w] = minweights[w-1] + min;
4162 
4163 #ifndef NDEBUG
4164  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4165  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4166  {
4167  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4168  assert(varidx >= 0 && varidx < nvars);
4169  assert(liftcoefs[varidx] == 1);
4170  assert(weights[varidx] >= min);
4171  }
4172 #endif
4173  }
4174  minweightslen = ngubconsGC1 + 1;
4175 
4176  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4177  fixedonesweight = 0;
4178  for( j = 0; j < ngubconsGC2; j++ )
4179  {
4180  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4181 
4182  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4183  assert(varidx >= 0 && varidx < nvars);
4184  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4185 
4186  fixedonesweight += weights[varidx];
4187  }
4188  assert(fixedonesweight >= 0);
4189 
4190  /* initializes right hand side of lifted valid inequality */
4191  *liftrhs = alpha0;
4192 
4193  /* sequentially up-lifts all variables in GFC1 GUBs */
4194  for( j = 0; j < ngubconsGFC1; j++ )
4195  {
4196  liftgubconsidx = gubconsGFC1[j];
4197  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4198 
4199  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4200  * compute minweight table via updated unfinished table and aleady upto date finished table;
4201  */
4202  k = 0;
4203  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4204  {
4205  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4206  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4207  assert(ngubconsGNC1 > 0);
4208 
4209  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4210  * are considered for the lifting, i.e., not capacity exceeding
4211  */
4212  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4213  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4214  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4215  assert(k >= 1);
4216 
4217  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4218  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4219  */
4220  weight = weights[liftgubvars[0]];
4221 
4222  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4223  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4224  for( w = ngubconsGNC1-1; w >= 1; w-- )
4225  {
4226  weightdiff1 = weightdiff2;
4227  weightdiff2 = unfinished[w] - weight;
4228 
4229  if( unfinished[w] < weightdiff1 )
4230  unfinished[w] = weightdiff1;
4231  else
4232  break;
4233  }
4234  ngubconsGNC1--;
4235 
4236  /* computes minweights table by combining unfished and fished tables */
4237  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4238  assert(minweights[0] == 0);
4239  }
4240  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4241  * are therefore not in the unfinished table
4242  */
4243  else
4244  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4245 
4246 #ifndef NDEBUG
4247  nliftgubC1 = k;
4248 #endif
4249  nliftgubvars = k;
4250  sumliftcoef = 0;
4251 
4252  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4253  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4254  {
4255  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4256  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4257  {
4258  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4259  weight = weights[liftvar];
4260  assert(weight > 0);
4261  assert(liftvar >= 0 && liftvar < nvars);
4262  assert(capacity - weight >= 0);
4263 
4264  /* put variable into array of variables in GUB that are considered for the lifting,
4265  * i.e., not capacity exceeding
4266  */
4267  liftgubvars[nliftgubvars] = liftvar;
4268  nliftgubvars++;
4269 
4270  /* knapsack problem is infeasible:
4271  * sets z = 0
4272  */
4273  if( capacity - fixedonesweight - weight < 0 )
4274  {
4275  z = 0;
4276  }
4277  /* knapsack problem is feasible:
4278  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4279  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4280  */
4281  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4282  {
4283  z = *liftrhs;
4284  }
4285  /* knapsack problem is feasible:
4286  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4287  */
4288  else
4289  {
4290  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4291  left = 0;
4292  right = (*liftrhs) + 1;
4293  while( left < right - 1 )
4294  {
4295  middle = (left + right) / 2;
4296  assert(0 <= middle && middle < minweightslen);
4297  if( minweights[middle] <= capacity - fixedonesweight - weight )
4298  left = middle;
4299  else
4300  right = middle;
4301  }
4302  assert(left == right - 1);
4303  assert(0 <= left && left < minweightslen);
4304  assert(minweights[left] <= capacity - fixedonesweight - weight);
4305  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4306 
4307  /* now z = left */
4308  z = left;
4309  assert(z <= *liftrhs);
4310  }
4311 
4312  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4313  liftcoef = (*liftrhs) - z;
4314  liftcoefs[liftvar] = liftcoef;
4315  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4316 
4317  /* updates activity of current valid inequality */
4318  (*cutact) += liftcoef * solvals[liftvar];
4319 
4320  /* updates sum of all lifting coefficients in GUB */
4321  sumliftcoef += liftcoefs[liftvar];
4322  }
4323  else
4324  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4325  }
4326  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4327  assert(nliftgubvars > nliftgubC1);
4328 
4329  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4330  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4331  * not needed for GF GUBs
4332  */
4333  if( sumliftcoef == 0 )
4334  {
4335  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4336  {
4337  weight = weights[liftgubvars[0]];
4338  /* update finished table and minweights table by applying special case of
4339  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4340  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4341  */
4342  for( w = minweightslen-1; w >= 1; w-- )
4343  {
4344  SCIP_Longint tmpval;
4345 
4346  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4347  finished[w] = MIN(finished[w], tmpval);
4348 
4349  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4350  minweights[w] = MIN(minweights[w], tmpval);
4351  }
4352  }
4353  else
4354  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4355 
4356  continue;
4357  }
4358 
4359  /* enlarges current minweights tables(finished, unfinished, minweights):
4360  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4361  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4362  * and sets minweights_i[w] = infinity for
4363  * 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
4364  */
4365  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4366  tmpsize = minweightssize;
4367  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4368  tmplen = minweightslen;
4369  tmpsize = minweightssize;
4370  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4371  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4372 
4373  /* update finished table and minweight table;
4374  * note that instead of computing minweight table from updated finished and updated unfinished table again
4375  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4376  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4377  * not needed because only finished table changed at this point and the change was "adding" one weight)
4378  *
4379  * update formular for minweight table is: minweight_i+1[w] =
4380  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4381  * formular for finished table has the same pattern.
4382  */
4383  for( w = minweightslen-1; w >= 0; w-- )
4384  {
4385  SCIP_Longint minminweight;
4386  SCIP_Longint minfinished;
4387 
4388  for( k = 0; k < nliftgubvars; k++ )
4389  {
4390  liftcoef = liftcoefs[liftgubvars[k]];
4391  weight = weights[liftgubvars[k]];
4392 
4393  if( w < liftcoef )
4394  {
4395  minfinished = MIN(finished[w], weight);
4396  minminweight = MIN(minweights[w], weight);
4397 
4398  finished[w] = minfinished;
4399  minweights[w] = minminweight;
4400  }
4401  else
4402  {
4403  SCIP_Longint tmpval;
4404 
4405  assert(w >= liftcoef);
4406 
4407  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4408  minfinished = MIN(finished[w], tmpval);
4409 
4410  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4411  minminweight = MIN(minweights[w], tmpval);
4412 
4413  finished[w] = minfinished;
4414  minweights[w] = minminweight;
4415  }
4416  }
4417  }
4418  assert(minweights[0] == 0);
4419  }
4420  assert(ngubconsGNC1 == 0);
4421 
4422  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4423  * therefore, only work with minweight table from here on
4424  */
4425 
4426  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4427  for( j = 0; j < ngubconsGC2; j++ )
4428  {
4429  liftgubconsidx = gubconsGC2[j];
4430 
4431  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4432  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4433  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4434  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4435 
4436  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4437  weight = weights[liftvar];
4438 
4439  assert(liftvar >= 0 && liftvar < nvars);
4440  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4441  assert(weight > 0);
4442 
4443  /* uses binary search to find
4444  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4445  */
4446  left = 0;
4447  right = minweightslen;
4448  while( left < right - 1 )
4449  {
4450  middle = (left + right) / 2;
4451  assert(0 <= middle && middle < minweightslen);
4452  if( minweights[middle] <= capacity - fixedonesweight + weight )
4453  left = middle;
4454  else
4455  right = middle;
4456  }
4457  assert(left == right - 1);
4458  assert(0 <= left && left < minweightslen);
4459  assert(minweights[left] <= capacity - fixedonesweight + weight);
4460  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4461 
4462  /* now z = left */
4463  z = left;
4464  assert(z >= *liftrhs);
4465 
4466  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4467  liftcoef = z - (*liftrhs);
4468  liftcoefs[liftvar] = liftcoef;
4469  assert(liftcoef >= 0);
4470 
4471  /* updates sum of weights of variables fixed to one */
4472  fixedonesweight -= weight;
4473 
4474  /* updates right-hand side of current valid inequality */
4475  (*liftrhs) += liftcoef;
4476  assert(*liftrhs >= alpha0);
4477 
4478  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4479  if( liftcoef == 0 )
4480  continue;
4481 
4482  /* updates activity of current valid inequality */
4483  (*cutact) += liftcoef * solvals[liftvar];
4484 
4485  /* enlarges current minweight table:
4486  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4487  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4488  * and sets minweights_i[w] = infinity for
4489  * 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
4490  */
4491  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4492 
4493  /* updates minweight table: minweight_i+1[w] =
4494  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4495  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4496  */
4497  for( w = minweightslen - 1; w >= 0; w-- )
4498  {
4499  if( w < liftcoef )
4500  {
4501  min = MIN(minweights[w], weight);
4502  minweights[w] = min;
4503  }
4504  else
4505  {
4506  SCIP_Longint tmpval;
4507 
4508  assert(w >= liftcoef);
4509 
4510  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4511  min = MIN(minweights[w], tmpval);
4512  minweights[w] = min;
4513  }
4514  }
4515  }
4516  assert(fixedonesweight == 0);
4517  assert(*liftrhs >= alpha0);
4518 
4519  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4520  for( j = 0; j < ngubconsGR; j++ )
4521  {
4522  liftgubconsidx = gubconsGR[j];
4523 
4524  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4525  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4526 
4527  sumliftcoef = 0;
4528  nliftgubvars = 0;
4529  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4530  {
4531  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4532  {
4533  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4534  weight = weights[liftvar];
4535  assert(weight > 0);
4536  assert(liftvar >= 0 && liftvar < nvars);
4537  assert(capacity - weight >= 0);
4538  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4539 
4540  /* put variable into array of variables in GUB that are considered for the lifting,
4541  * i.e., not capacity exceeding
4542  */
4543  liftgubvars[nliftgubvars] = liftvar;
4544  nliftgubvars++;
4545 
4546  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4547  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4548  */
4549  if( minweights[*liftrhs] <= capacity - weight )
4550  {
4551  z = *liftrhs;
4552  }
4553  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4554  */
4555  else
4556  {
4557  left = 0;
4558  right = (*liftrhs) + 1;
4559  while( left < right - 1 )
4560  {
4561  middle = (left + right) / 2;
4562  assert(0 <= middle && middle < minweightslen);
4563  if( minweights[middle] <= capacity - weight )
4564  left = middle;
4565  else
4566  right = middle;
4567  }
4568  assert(left == right - 1);
4569  assert(0 <= left && left < minweightslen);
4570  assert(minweights[left] <= capacity - weight);
4571  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4572 
4573  /* now z = left */
4574  z = left;
4575  assert(z <= *liftrhs);
4576  }
4577  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4578  liftcoef = (*liftrhs) - z;
4579  liftcoefs[liftvar] = liftcoef;
4580  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4581 
4582  /* updates activity of current valid inequality */
4583  (*cutact) += liftcoef * solvals[liftvar];
4584 
4585  /* updates sum of all lifting coefficients in GUB */
4586  sumliftcoef += liftcoefs[liftvar];
4587  }
4588  else
4589  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4590  }
4591  assert(nliftgubvars >= 1); /* at least one variable is in R */
4592 
4593  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4594  if( sumliftcoef == 0 )
4595  continue;
4596 
4597  /* updates minweight table: minweight_i+1[w] =
4598  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4599  */
4600  for( w = *liftrhs; w >= 0; w-- )
4601  {
4602  for( k = 0; k < nliftgubvars; k++ )
4603  {
4604  liftcoef = liftcoefs[liftgubvars[k]];
4605  weight = weights[liftgubvars[k]];
4606 
4607  if( w < liftcoef )
4608  {
4609  min = MIN(minweights[w], weight);
4610  minweights[w] = min;
4611  }
4612  else
4613  {
4614  SCIP_Longint tmpval;
4615 
4616  assert(w >= liftcoef);
4617 
4618  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4619  min = MIN(minweights[w], tmpval);
4620  minweights[w] = min;
4621  }
4622  }
4623  }
4624  assert(minweights[0] == 0);
4625  }
4626 
4627  /* frees temporary memory */
4628  SCIPfreeBufferArray(scip, &minweights);
4629  SCIPfreeBufferArray(scip, &finished);
4630  SCIPfreeBufferArray(scip, &unfinished);
4631  SCIPfreeBufferArray(scip, &liftgubvars);
4632  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4633  SCIPfreeBufferArray(scip, &gubconsGNC1);
4634 
4635  return SCIP_OKAY;
4636 }
4637 
4638 /** lifts given minimal cover inequality
4639  * \f[
4640  * \sum_{j \in C} x_j \leq |C| - 1
4641  * \f]
4642  * valid for
4643  * \f[
4644  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4645  * \f]
4646  * to a valid inequality
4647  * \f[
4648  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4649  * \f]
4650  * for
4651  * \f[
4652  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4653  * \f]
4654  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4655  */
4656 static
4658  SCIP* scip, /**< SCIP data structure */
4659  SCIP_VAR** vars, /**< variables in knapsack constraint */
4660  int nvars, /**< number of variables in knapsack constraint */
4661  int ntightened, /**< number of variables with tightened upper bound */
4662  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4663  SCIP_Longint capacity, /**< capacity of knapsack */
4664  SCIP_Real* solvals, /**< solution values of all problem variables */
4665  int* covervars, /**< cover variables */
4666  int* noncovervars, /**< noncover variables */
4667  int ncovervars, /**< number of cover variables */
4668  int nnoncovervars, /**< number of noncover variables */
4669  SCIP_Longint coverweight, /**< weight of cover */
4670  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4671  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4672  )
4673 {
4674  SCIP_Longint* maxweightsums;
4675  SCIP_Longint* intervalends;
4676  SCIP_Longint* rhos;
4677  SCIP_Real* sortkeys;
4678  SCIP_Longint lambda;
4679  int j;
4680  int h;
4681 
4682  assert(scip != NULL);
4683  assert(vars != NULL);
4684  assert(nvars >= 0);
4685  assert(weights != NULL);
4686  assert(capacity >= 0);
4687  assert(solvals != NULL);
4688  assert(covervars != NULL);
4689  assert(noncovervars != NULL);
4690  assert(ncovervars > 0 && ncovervars <= nvars);
4691  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4692  assert(ncovervars + nnoncovervars == nvars - ntightened);
4693  assert(liftcoefs != NULL);
4694  assert(cutact != NULL);
4695 
4696  /* allocates temporary memory */
4697  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4698  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4699  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4700  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4701 
4702  /* initializes data structures */
4703  BMSclearMemoryArray(liftcoefs, nvars);
4704  *cutact = 0.0;
4705 
4706  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4707  * and calculates activity of current valid inequality
4708  */
4709  for( j = 0; j < ncovervars; j++ )
4710  {
4711  assert(liftcoefs[covervars[j]] == 0.0);
4712  liftcoefs[covervars[j]] = 1.0;
4713  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4714  (*cutact) += solvals[covervars[j]];
4715  }
4716  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4717 
4718  /* calculates weight excess of cover C */
4719  lambda = coverweight - capacity;
4720  assert(lambda > 0);
4721 
4722  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4723  maxweightsums[0] = 0;
4724  for( h = 1; h <= ncovervars; h++ )
4725  {
4726  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4727  intervalends[h-1] = maxweightsums[h] - lambda;
4728  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4729  }
4730 
4731  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4732  for( j = 0; j < nnoncovervars; j++ )
4733  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4734  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4735 
4736  /* calculates lifting coefficient for all variables in N\C */
4737  h = 0;
4738  for( j = 0; j < nnoncovervars; j++ )
4739  {
4740  int liftvar;
4741  SCIP_Longint weight;
4742  SCIP_Real liftcoef;
4743 
4744  liftvar = noncovervars[j];
4745  weight = weights[liftvar];
4746 
4747  while( intervalends[h] < weight )
4748  h++;
4749 
4750  if( h == 0 )
4751  liftcoef = h;
4752  else
4753  {
4754  if( weight <= intervalends[h-1] + rhos[h] )
4755  {
4756  SCIP_Real tmp1;
4757  SCIP_Real tmp2;
4758  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4759  tmp2 = (SCIP_Real) rhos[1];
4760  liftcoef = h - ( tmp1 / tmp2 );
4761  }
4762  else
4763  liftcoef = h;
4764  }
4765 
4766  /* sets lifting coefficient */
4767  assert(liftcoefs[liftvar] == 0.0);
4768  liftcoefs[liftvar] = liftcoef;
4769 
4770  /* updates activity of current valid inequality */
4771  (*cutact) += liftcoef * solvals[liftvar];
4772  }
4773 
4774  /* frees temporary memory */
4775  SCIPfreeBufferArray(scip, &rhos);
4776  SCIPfreeBufferArray(scip, &intervalends);
4777  SCIPfreeBufferArray(scip, &maxweightsums);
4778  SCIPfreeBufferArray(scip, &sortkeys);
4779 
4780  return SCIP_OKAY;
4781 }
4782 
4783 
4784 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4785  * given knapsack problem
4786 */
4787 static
4789  SCIP* scip, /**< SCIP data structure */
4790  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4791  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4792  SCIP_VAR** vars, /**< variables in knapsack constraint */
4793  int nvars, /**< number of variables in knapsack constraint */
4794  int ntightened, /**< number of variables with tightened upper bound */
4795  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4796  SCIP_Longint capacity, /**< capacity of knapsack */
4797  SCIP_Real* solvals, /**< solution values of all problem variables */
4798  int* mincovervars, /**< mincover variables */
4799  int* nonmincovervars, /**< nonmincover variables */
4800  int nmincovervars, /**< number of mincover variables */
4801  int nnonmincovervars, /**< number of nonmincover variables */
4802  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4803  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4804  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4805  int* ncuts /**< pointer to add up the number of found cuts */
4806  )
4807 {
4808  int* varsC1;
4809  int* varsC2;
4810  int* varsF;
4811  int* varsR;
4812  int nvarsC1;
4813  int nvarsC2;
4814  int nvarsF;
4815  int nvarsR;
4816  SCIP_Real cutact;
4817  int* liftcoefs;
4818  int liftrhs;
4819 
4820  assert( cutoff != NULL );
4821  *cutoff = FALSE;
4822 
4823  /* allocates temporary memory */
4824  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4825  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4826  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4827  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4828  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4829 
4830  /* 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
4831  * as follows
4832  * C_2 = { j in C : x*_j = 1 } and
4833  * C_1 = C\C_2
4834  */
4835  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4836  assert(nvarsC1 + nvarsC2 == nmincovervars);
4837  assert(nmincovervars > 0);
4838  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4839 
4840  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4841  if( nvarsC1 < 2 && nvarsC2 > 0)
4842  {
4843  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4844  assert(nvarsC1 >= 1);
4845  }
4846  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4847 
4848  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4849  * R = { j in N\C : x*_j = 0 } and
4850  * F = (N\C)\F
4851  */
4852  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4853  assert(nvarsF + nvarsR == nnonmincovervars);
4854  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4855 
4856  /* lift cuts without GUB information */
4857  if( gubset == NULL )
4858  {
4859  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4860  * lifting procedure
4861  */
4862  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4863 
4864  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4865  *
4866  * 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 }
4867  *
4868  * 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
4869  *
4870  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4871  *
4872  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4873  * up-lifting for the variables in R according to the second level lifting sequence
4874  */
4875  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4876  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4877  }
4878  /* lift cuts with GUB information */
4879  else
4880  {
4881  int* gubconsGC1;
4882  int* gubconsGC2;
4883  int* gubconsGFC1;
4884  int* gubconsGR;
4885  int ngubconsGC1;
4886  int ngubconsGC2;
4887  int ngubconsGFC1;
4888  int ngubconsGR;
4889  int ngubconss;
4890  int nconstightened;
4891  int maxgubvarssize;
4892 
4893  assert(nvars == gubset->nvars);
4894 
4895  ngubconsGC1 = 0;
4896  ngubconsGC2 = 0;
4897  ngubconsGFC1 = 0;
4898  ngubconsGR = 0;
4899  ngubconss = gubset->ngubconss;
4900  nconstightened = 0;
4901  maxgubvarssize = 0;
4902 
4903  /* allocates temporary memory */
4904  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4905  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4906  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4907  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4908 
4909  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4910  * the GUBs for the sequential GUB wise lifting procedure
4911  */
4912  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4913  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4914  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4915 
4916  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4917  *
4918  * 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,
4919  * sum_{j in Q_i} x_j <= 1, forall i in I }
4920  *
4921  * 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
4922  *
4923  * 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 },
4924  *
4925  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4926  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4927  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4928  */
4929  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4930  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4931  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4932 
4933  /* frees temporary memory */
4934  SCIPfreeBufferArray(scip, &gubconsGR);
4935  SCIPfreeBufferArray(scip, &gubconsGFC1);
4936  SCIPfreeBufferArray(scip, &gubconsGC2);
4937  SCIPfreeBufferArray(scip, &gubconsGC1);
4938  }
4939 
4940  /* checks, if lifting yielded a violated cut */
4941  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4942  {
4943  SCIP_ROW* row;
4944  char name[SCIP_MAXSTRLEN];
4945  int j;
4946 
4947  /* creates LP row */
4948  assert( cons == NULL || sepa == NULL );
4949  if ( cons != NULL )
4950  {
4952  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4953  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4954  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4955  }
4956  else if ( sepa != NULL )
4957  {
4958  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4959  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4960  }
4961  else
4962  {
4963  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
4964  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4965  }
4966 
4967  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4968  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4969  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4970  for( j = 0; j < nvarsC1; j++ )
4971  {
4972  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4973  }
4974  for( j = 0; j < nvarsC2; j++ )
4975  {
4976  if( liftcoefs[varsC2[j]] > 0 )
4977  {
4978  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4979  }
4980  }
4981  for( j = 0; j < nvarsF; j++ )
4982  {
4983  if( liftcoefs[varsF[j]] > 0 )
4984  {
4985  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4986  }
4987  }
4988  for( j = 0; j < nvarsR; j++ )
4989  {
4990  if( liftcoefs[varsR[j]] > 0 )
4991  {
4992  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4993  }
4994  }
4995  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4996 
4997  /* checks, if cut is violated enough */
4998  if( SCIPisCutEfficacious(scip, sol, row) )
4999  {
5000  if( cons != NULL )
5001  {
5002  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5003  }
5004  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5005  (*ncuts)++;
5006  }
5007  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5008  }
5009 
5010  /* frees temporary memory */
5011  SCIPfreeBufferArray(scip, &liftcoefs);
5012  SCIPfreeBufferArray(scip, &varsR);
5013  SCIPfreeBufferArray(scip, &varsF);
5014  SCIPfreeBufferArray(scip, &varsC2);
5015  SCIPfreeBufferArray(scip, &varsC1);
5016 
5017  return SCIP_OKAY;
5018 }
5019 
5020 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5021 static
5023  SCIP* scip, /**< SCIP data structure */
5024  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5025  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5026  SCIP_VAR** vars, /**< variables in knapsack constraint */
5027  int nvars, /**< number of variables in knapsack constraint */
5028  int ntightened, /**< number of variables with tightened upper bound */
5029  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5030  SCIP_Longint capacity, /**< capacity of knapsack */
5031  SCIP_Real* solvals, /**< solution values of all problem variables */
5032  int* feassetvars, /**< variables in feasible set */
5033  int* nonfeassetvars, /**< variables not in feasible set */
5034  int nfeassetvars, /**< number of variables in feasible set */
5035  int nnonfeassetvars, /**< number of variables not in feasible set */
5036  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5037  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5038  int* ncuts /**< pointer to add up the number of found cuts */
5039  )
5040 {
5041  int* varsT1;
5042  int* varsT2;
5043  int* varsF;
5044  int* varsR;
5045  int* liftcoefs;
5046  SCIP_Real cutact;
5047  int nvarsT1;
5048  int nvarsT2;
5049  int nvarsF;
5050  int nvarsR;
5051  int liftrhs;
5052  int j;
5053 
5054  assert( cutoff != NULL );
5055  *cutoff = FALSE;
5056 
5057  /* allocates temporary memory */
5058  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5059  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5060  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5061  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5062  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5063 
5064  /* 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
5065  * as follows
5066  * T_2 = { j in T : x*_j = 1 } and
5067  * T_1 = T\T_2
5068  */
5069  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5070  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5071 
5072  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5073  if( nvarsT1 == 0 && nvarsT2 > 0)
5074  {
5075  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5076  assert(nvarsT1 == 1);
5077  }
5078  assert(nvarsT2 == 0 || nvarsT1 > 0);
5079 
5080  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5081  * R = { j in N\T : x*_j = 0 } and
5082  * F = (N\T)\F
5083  */
5084  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5085  assert(nvarsF + nvarsR == nnonfeassetvars);
5086  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5087 
5088  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5089  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5090  * is included in the sorting routine)
5091  */
5092  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5093 
5094  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5095  *
5096  * 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 }
5097  *
5098  * 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
5099  *
5100  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5101  *
5102  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5103  * up-lifting for the variabels in R according to the second level lifting sequence
5104  */
5105  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5106  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5107 
5108  /* checks, if lifting yielded a violated cut */
5109  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5110  {
5111  SCIP_ROW* row;
5112  char name[SCIP_MAXSTRLEN];
5113 
5114  /* creates LP row */
5115  assert( cons == NULL || sepa == NULL );
5116  if( cons != NULL )
5117  {
5119  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5120  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5121  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5122  }
5123  else if ( sepa != NULL )
5124  {
5125  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5126  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5127  }
5128  else
5129  {
5130  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%" SCIP_LONGINT_FORMAT "", *ncuts);
5131  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5132  }
5133 
5134  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5135  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5136  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5137  for( j = 0; j < nvarsT1; j++ )
5138  {
5139  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5140  }
5141  for( j = 0; j < nvarsT2; j++ )
5142  {
5143  if( liftcoefs[varsT2[j]] > 0 )
5144  {
5145  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5146  }
5147  }
5148  for( j = 0; j < nvarsF; j++ )
5149  {
5150  if( liftcoefs[varsF[j]] > 0 )
5151  {
5152  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5153  }
5154  }
5155  for( j = 0; j < nvarsR; j++ )
5156  {
5157  if( liftcoefs[varsR[j]] > 0 )
5158  {
5159  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5160  }
5161  }
5162  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5163 
5164  /* checks, if cut is violated enough */
5165  if( SCIPisCutEfficacious(scip, sol, row) )
5166  {
5167  if( cons != NULL )
5168  {
5169  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5170  }
5171  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5172  (*ncuts)++;
5173  }
5174  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5175  }
5176 
5177  /* frees temporary memory */
5178  SCIPfreeBufferArray(scip, &liftcoefs);
5179  SCIPfreeBufferArray(scip, &varsR);
5180  SCIPfreeBufferArray(scip, &varsF);
5181  SCIPfreeBufferArray(scip, &varsT2);
5182  SCIPfreeBufferArray(scip, &varsT1);
5183 
5184  return SCIP_OKAY;
5185 }
5186 
5187 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5188 static
5190  SCIP* scip, /**< SCIP data structure */
5191  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5192  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5193  SCIP_VAR** vars, /**< variables in knapsack constraint */
5194  int nvars, /**< number of variables in knapsack constraint */
5195  int ntightened, /**< number of variables with tightened upper bound */
5196  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5197  SCIP_Longint capacity, /**< capacity of knapsack */
5198  SCIP_Real* solvals, /**< solution values of all problem variables */
5199  int* mincovervars, /**< mincover variables */
5200  int* nonmincovervars, /**< nonmincover variables */
5201  int nmincovervars, /**< number of mincover variables */
5202  int nnonmincovervars, /**< number of nonmincover variables */
5203  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5204  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5205  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5206  int* ncuts /**< pointer to add up the number of found cuts */
5207  )
5208 {
5209  SCIP_Real* realliftcoefs;
5210  SCIP_Real cutact;
5211  int liftrhs;
5212 
5213  assert( cutoff != NULL );
5214  *cutoff = FALSE;
5215  cutact = 0.0;
5216 
5217  /* allocates temporary memory */
5218  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5219 
5220  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5221  *
5222  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5223  *
5224  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5225  *
5226  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5227  *
5228  * uses superadditive up-lifting for the variables in N\C.
5229  */
5230  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5231  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5232  liftrhs = nmincovervars - 1;
5233 
5234  /* checks, if lifting yielded a violated cut */
5235  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5236  {
5237  SCIP_ROW* row;
5238  char name[SCIP_MAXSTRLEN];
5239  int j;
5240 
5241  /* creates LP row */
5242  assert( cons == NULL || sepa == NULL );
5243  if ( cons != NULL )
5244  {
5246  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5247  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5248  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5249  }
5250  else if ( sepa != NULL )
5251  {
5252  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5253  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5254  }
5255  else
5256  {
5257  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%" SCIP_LONGINT_FORMAT "", *ncuts);
5258  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5259  }
5260 
5261  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5262  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5263  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5264  for( j = 0; j < nmincovervars; j++ )
5265  {
5266  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5267  }
5268  for( j = 0; j < nnonmincovervars; j++ )
5269  {
5270  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5271  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5272  {
5273  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5274  }
5275  }
5276  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5277 
5278  /* checks, if cut is violated enough */
5279  if( SCIPisCutEfficacious(scip, sol, row) )
5280  {
5281  if( cons != NULL )
5282  {
5283  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5284  }
5285  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5286  (*ncuts)++;
5287  }
5288  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5289  }
5290 
5291  /* frees temporary memory */
5292  SCIPfreeBufferArray(scip, &realliftcoefs);
5293 
5294  return SCIP_OKAY;
5295 }
5296 
5297 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5298  * 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
5299  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5300  * note that all variables with x*_j = 1 will be removed last
5301  */
5302 static
5304  SCIP* scip, /**< SCIP data structure */
5305  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5306  SCIP_Longint capacity, /**< capacity of knapsack */
5307  SCIP_Real* solvals, /**< solution values of all problem variables */
5308  int* covervars, /**< pointer to store cover variables */
5309  int* noncovervars, /**< pointer to store noncover variables */
5310  int* ncovervars, /**< pointer to store number of cover variables */
5311  int* nnoncovervars, /**< pointer to store number of noncover variables */
5312  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5313  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5314  )
5315 {
5316  SORTKEYPAIR** sortkeypairs;
5317  SCIP_Longint minweight;
5318  int nsortkeypairs;
5319  int minweightidx;
5320  int j;
5321  int k;
5322 
5323  assert(scip != NULL);
5324  assert(covervars != NULL);
5325  assert(noncovervars != NULL);
5326  assert(ncovervars != NULL);
5327  assert(*ncovervars > 0);
5328  assert(nnoncovervars != NULL);
5329  assert(*nnoncovervars >= 0);
5330  assert(coverweight != NULL);
5331  assert(*coverweight > 0);
5332  assert(*coverweight > capacity);
5333 
5334  /* allocates temporary memory */
5335  nsortkeypairs = *ncovervars;
5336  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5337 
5338  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5339  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5340  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5341  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5342  */
5343  assert(*ncovervars == nsortkeypairs);
5344  if( modtransused )
5345  {
5346  for( j = 0; j < *ncovervars; j++ )
5347  {
5348  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5349 
5350  sortkeypairs[j]->key1 = solvals[covervars[j]];
5351  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5352  }
5353  }
5354  else
5355  {
5356  for( j = 0; j < *ncovervars; j++ )
5357  {
5358  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5359 
5360  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5361  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5362  }
5363  }
5364  SCIPsortPtrInt((void**)sortkeypairs, covervars, compSortkeypairs, *ncovervars);
5365 
5366  /* gets j' with a_j' = min{ a_j : j in C } */
5367  minweightidx = 0;
5368  minweight = weights[covervars[minweightidx]];
5369  for( j = 1; j < *ncovervars; j++ )
5370  {
5371  if( weights[covervars[j]] <= minweight )
5372  {
5373  minweightidx = j;
5374  minweight = weights[covervars[minweightidx]];
5375  }
5376  }
5377  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5378  assert(minweight > 0 && minweight <= *coverweight);
5379 
5380  j = 0;
5381  /* removes variables from C until the remaining variables form a minimal cover */
5382  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5383  {
5384  assert(minweightidx >= j);
5385  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5386 
5387  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5388  if( (*coverweight) - weights[covervars[j]] <= capacity )
5389  {
5390  ++j;
5391  continue;
5392  }
5393 
5394  /* adds j to N\C */
5395  noncovervars[*nnoncovervars] = covervars[j];
5396  (*nnoncovervars)++;
5397 
5398  /* removes j from C */
5399  (*coverweight) -= weights[covervars[j]];
5400  for( k = j; k < (*ncovervars) - 1; k++ )
5401  covervars[k] = covervars[k+1];
5402  (*ncovervars)--;
5403 
5404  /* updates j' with a_j' = min{ a_j : j in C } */
5405  if( j == minweightidx )
5406  {
5407  minweightidx = 0;
5408  minweight = weights[covervars[minweightidx]];
5409  for( k = 1; k < *ncovervars; k++ )
5410  {
5411  if( weights[covervars[k]] <= minweight )
5412  {
5413  minweightidx = k;
5414  minweight = weights[covervars[minweightidx]];
5415  }
5416  }
5417  assert(minweight > 0 && minweight <= *coverweight);
5418  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5419  }
5420  else
5421  {
5422  assert(minweightidx > j);
5423  minweightidx--;
5424  }
5425  /* j needs to stay the same */
5426  }
5427  assert((*coverweight) > capacity);
5428  assert((*coverweight) - minweight <= capacity);
5429 
5430  /* frees temporary memory */
5431  for( j = nsortkeypairs-1; j >= 0; j-- )
5432  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5433  SCIPfreeBufferArray(scip, &sortkeypairs);
5434 
5435  return SCIP_OKAY;
5436 }
5437 
5438 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5439  * they were chosen to be in C_init:
5440  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5441  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5442  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5443  * and all subsequent feasible sets.
5444  */
5445 static
5447  SCIP* scip, /**< SCIP data structure */
5448  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5449  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5450  SCIP_VAR** vars, /**< variables in knapsack constraint */
5451  int nvars, /**< number of variables in knapsack constraint */
5452  int ntightened, /**< number of variables with tightened upper bound */
5453  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5454  SCIP_Longint capacity, /**< capacity of knapsack */
5455  SCIP_Real* solvals, /**< solution values of all problem variables */
5456  int* covervars, /**< pointer to store cover variables */
5457  int* noncovervars, /**< pointer to store noncover variables */
5458  int* ncovervars, /**< pointer to store number of cover variables */
5459  int* nnoncovervars, /**< pointer to store number of noncover variables */
5460  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5461  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5462  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5463  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5464  int* ncuts /**< pointer to add up the number of found cuts */
5465  )
5466 {
5467  SCIP_Real* sortkeys;
5468  int j;
5469  int k;
5470 
5471  assert(scip != NULL);
5472  assert(covervars != NULL);
5473  assert(noncovervars != NULL);
5474  assert(ncovervars != NULL);
5475  assert(*ncovervars > 0);
5476  assert(nnoncovervars != NULL);
5477  assert(*nnoncovervars >= 0);
5478  assert(coverweight != NULL);
5479  assert(*coverweight > 0);
5480  assert(*coverweight > capacity);
5481  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5482  assert(cutoff != NULL);
5483 
5484  *cutoff = FALSE;
5485 
5486  /* allocates temporary memory */
5487  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5488 
5489  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5490  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5491  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5492  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5493  */
5494  if( modtransused )
5495  {
5496  for( j = 0; j < *ncovervars; j++ )
5497  {
5498  sortkeys[j] = solvals[covervars[j]];
5499  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5500  }
5501  }
5502  else
5503  {
5504  for( j = 0; j < *ncovervars; j++ )
5505  {
5506  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5507  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5508  }
5509  }
5510  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5511 
5512  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5513  * in addition to an extended weight inequality this gives cardinality inequalities */
5514  while( *ncovervars >= 2 )
5515  {
5516  /* adds first element of C_init to N\C_init */
5517  noncovervars[*nnoncovervars] = covervars[0];
5518  (*nnoncovervars)++;
5519 
5520  /* removes first element from C_init */
5521  (*coverweight) -= weights[covervars[0]];
5522  for( k = 0; k < (*ncovervars) - 1; k++ )
5523  covervars[k] = covervars[k+1];
5524  (*ncovervars)--;
5525 
5526  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5527  if( (*coverweight) <= capacity )
5528  {
5529  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5530  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5531  }
5532 
5533  /* stop if cover is too large */
5534  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5535  break;
5536  }
5537 
5538  /* frees temporary memory */
5539  SCIPfreeBufferArray(scip, &sortkeys);
5540 
5541  return SCIP_OKAY;
5542 }
5543 
5544 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5546  SCIP* scip, /**< SCIP data structure */
5547  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5548  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5549  SCIP_VAR** vars, /**< variables in knapsack constraint */
5550  int nvars, /**< number of variables in knapsack constraint */
5551  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5552  SCIP_Longint capacity, /**< capacity of knapsack */
5553  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5554  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5555  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5556  int* ncuts /**< pointer to add up the number of found cuts */
5557  )
5558 {
5559  SCIP_Real* solvals;
5560  int* covervars;
5561  int* noncovervars;
5562  SCIP_Bool coverfound;
5563  SCIP_Bool fractional;
5564  SCIP_Bool modtransused;
5565  SCIP_Longint coverweight;
5566  int ncovervars;
5567  int nnoncovervars;
5568  int ntightened;
5569 
5570  assert(scip != NULL);
5571  assert(capacity >= 0);
5572  assert(cutoff != NULL);
5573  assert(ncuts != NULL);
5574 
5575  *cutoff = FALSE;
5576 
5577  if( nvars == 0 )
5578  return SCIP_OKAY;
5579 
5580  assert(vars != NULL);
5581  assert(nvars > 0);
5582  assert(weights != NULL);
5583 
5584  /* increase age of constraint (age is reset to zero, if a cut was found) */
5585  if( cons != NULL )
5586  {
5587  SCIP_CALL( SCIPincConsAge(scip, cons) );
5588  }
5589 
5590  /* allocates temporary memory */
5591  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5592  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5593  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5594 
5595  /* gets solution values of all problem variables */
5596  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5597 
5598 #ifdef SCIP_DEBUG
5599  {
5600  int i;
5601 
5602  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5603  cons == NULL ? "-" : SCIPconsGetName(cons));
5604  for( i = 0; i < nvars; ++i )
5605  {
5606  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5607  }
5608  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5609  }
5610 #endif
5611 
5612  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5613  */
5614  if( usegubs )
5615  {
5616  SCIP_GUBSET* gubset;
5617 
5618  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5619 
5620  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5621  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5622 
5623  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5624  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5625  assert(gubset->ngubconss <= nvars);
5626 
5627  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5628  * MODIFIED transformed separation problem and taking into account the following fixing:
5629  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5630  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5631  * if one exists
5632  */
5633  modtransused = TRUE;
5634  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5635  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5636 
5637  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5638 
5639  /* if x* is not fractional we stop the separation routine */
5640  if( !fractional )
5641  {
5642  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5643 
5644  /* frees memory for GUB set data structure */
5645  SCIP_CALL( GUBsetFree(scip, &gubset) );
5646 
5647  goto TERMINATE;
5648  }
5649 
5650  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5651  if( coverfound )
5652  {
5653  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5654  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5655  */
5656  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5657  &nnoncovervars, &coverweight, modtransused) );
5658 
5659  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5660  if( gubset->ngubconss < nvars )
5661  {
5662  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5663  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5664  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5665  }
5666  else
5667  {
5668  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5669  * GUB information
5670  */
5671  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5672  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5673  }
5674  }
5675 
5676  /* frees memory for GUB set data structure */
5677  SCIP_CALL( GUBsetFree(scip, &gubset) );
5678  }
5679  else
5680  {
5681  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5682  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5683  */
5684 
5685  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5686  * MODIFIED transformed separation problem and taking into account the following fixing:
5687  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5688  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5689  * if one exists
5690  */
5691  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5692  modtransused = TRUE;
5693  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5694  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5695  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5696 
5697  /* if x* is not fractional we stop the separation routine */
5698  if( !fractional )
5699  goto TERMINATE;
5700 
5701  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5702  if( coverfound )
5703  {
5704  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5705  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5706  */
5707  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5708  &nnoncovervars, &coverweight, modtransused) );
5709 
5710  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5711  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5712  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5713 
5714  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5715  {
5716  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5717  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5718  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5719  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5720  }
5721  }
5722  }
5723 
5724  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5725  if ( ! (*cutoff) )
5726  {
5727  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5728  * transformed separation problem and taking into account the following fixing:
5729  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5730  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5731  * if one exists
5732  */
5733  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5734  modtransused = FALSE;
5735  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5736  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5737  assert(fractional);
5738  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5739 
5740  /* if no cover was found we stop the separation routine */
5741  if( coverfound )
5742  {
5743  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5744  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5745  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5746  */
5747  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5748  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5749  }
5750  }
5751 
5752  TERMINATE:
5753  /* frees temporary memory */
5754  SCIPfreeBufferArray(scip, &noncovervars);
5755  SCIPfreeBufferArray(scip, &covervars);
5756  SCIPfreeBufferArray(scip, &solvals);
5757 
5758  return SCIP_OKAY;
5759 }
5760 
5761 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5763  SCIP* scip, /**< SCIP data structure */
5764  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5765  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5766  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5767  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5768  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5769  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5770  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5771  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5772  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5773  int* ncuts /**< pointer to add up the number of found cuts */
5774  )
5775 {
5776  SCIP_VAR** binvars;
5777  SCIP_VAR** consvars;
5778  SCIP_Real* binvals;
5779  SCIP_Longint* consvals;
5780  SCIP_Longint minact;
5781  SCIP_Longint maxact;
5782  SCIP_Real intscalar;
5783  SCIP_Bool success;
5784  int nbinvars;
5785  int nconsvars;
5786  int i;
5787 
5788  int* tmpindices;
5789  int tmp;
5790  SCIP_CONSHDLR* conshdlr;
5791  SCIP_CONSHDLRDATA* conshdlrdata;
5792  SCIP_Bool noknapsackconshdlr;
5793  SCIP_Bool usegubs;
5794 
5795  assert(nknapvars > 0);
5796  assert(knapvars != NULL);
5797  assert(cutoff != NULL);
5798 
5799  tmpindices = NULL;
5800 
5801  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5802  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5803 
5804  binvars = SCIPgetVars(scip);
5805 
5806  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5807  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5808 
5809  *cutoff = FALSE;
5810 
5811  if( nbinvars == 0 )
5812  return SCIP_OKAY;
5813 
5814  /* set up data structures */
5815  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5816  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5817 
5818  /* get conshdlrdata to use cleared memory */
5819  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5820  if( conshdlr == NULL )
5821  {
5822  noknapsackconshdlr = TRUE;
5823  usegubs = DEFAULT_USEGUBS;
5824 
5825  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5826  BMSclearMemoryArray(binvals, nbinvars);
5827  }
5828  else
5829  {
5830  noknapsackconshdlr = FALSE;
5831  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5832  assert(conshdlrdata != NULL);
5833  usegubs = conshdlrdata->usegubs;
5834 
5835  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5836 
5837  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5838  * change their types to SCIP_VARTYPE_BINARY during presolving
5839  */
5840  if( conshdlrdata->reals1size == 0 )
5841  {
5842  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5843  conshdlrdata->reals1size = 1;
5844  conshdlrdata->reals1[0] = 0.0;
5845  }
5846 
5847  assert(conshdlrdata->reals1size > 0);
5848 
5849  /* next if condition should normally not be true, because it means that presolving has created more binary
5850  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5851  * transform all integers into their binary representation then it maybe happens
5852  */
5853  if( conshdlrdata->reals1size < nbinvars )
5854  {
5855  int oldsize = conshdlrdata->reals1size;
5856 
5857  conshdlrdata->reals1size = nbinvars;
5858  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5859  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5860  }
5861  binvals = conshdlrdata->reals1;
5862 
5863  /* check for cleared array, all entries have to be zero */
5864 #ifndef NDEBUG
5865  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5866  {
5867  assert(binvals[tmp] == 0);
5868  }
5869 #endif
5870  }
5871 
5872  tmp = 0;
5873 
5874  /* relax continuous knapsack constraint:
5875  * 1. make all variables binary:
5876  * if x_j is continuous or integer variable substitute:
5877  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5878  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5879  * 2. convert coefficients of all variables to positive integers:
5880  * - scale all coefficients a_j to a~_j integral
5881  * - substitute x~_j = 1 - x_j if a~_j < 0
5882  */
5883 
5884  /* replace integer and continuous variables with binary variables */
5885  for( i = 0; i < nknapvars; i++ )
5886  {
5887  SCIP_VAR* var;
5888 
5889  var = knapvars[i];
5890 
5891  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5892  {
5893  SCIP_Real solval;
5894  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5895 
5896  solval = SCIPgetSolVal(scip, sol, var);
5897 
5898  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5899  if( SCIPisFeasLT(scip, solval, 0.0 )
5900  || SCIPisFeasGT(scip, solval, 1.0) )
5901  {
5902  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5903  solval, SCIPvarGetName(var));
5904  goto TERMINATE;
5905  }
5906 
5907  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5908  if( !noknapsackconshdlr )
5909  {
5910  assert(tmpindices != NULL);
5911 
5912  tmpindices[tmp] = SCIPvarGetProbindex(var);
5913  ++tmp;
5914  }
5915  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5916  }
5917  else if( valscale * knapvals[i] > 0.0 )
5918  {
5919  SCIP_VAR** zvlb;
5920  SCIP_Real* bvlb;
5921  SCIP_Real* dvlb;
5922  SCIP_Real bestlbsol;
5923  int bestlbtype;
5924  int nvlb;
5925  int j;
5926 
5927  /* a_j > 0: substitution with lb or vlb */
5928  nvlb = SCIPvarGetNVlbs(var);
5929  zvlb = SCIPvarGetVlbVars(var);
5930  bvlb = SCIPvarGetVlbCoefs(var);
5931  dvlb = SCIPvarGetVlbConstants(var);
5932 
5933  /* search for lb or vlb with maximal bound value */
5934  bestlbsol = SCIPvarGetLbGlobal(var);
5935  bestlbtype = -1;
5936  for( j = 0; j < nvlb; j++ )
5937  {
5938  /* use only numerical stable vlb with binary variable z */
5939  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5940  {
5941  SCIP_Real vlbsol;
5942 
5943  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5944  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5945  {
5946  *cutoff = TRUE;
5947  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5949  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5950  goto TERMINATE;
5951  }
5952 
5953  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5954  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5955  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5956  {
5957  bestlbsol = vlbsol;
5958  bestlbtype = j;
5959  }
5960  }
5961  }
5962 
5963  /* if no lb or vlb with binary variable was found, we have to abort */
5964  if( SCIPisInfinity(scip, -bestlbsol) )
5965  goto TERMINATE;
5966 
5967  if( bestlbtype == -1 )
5968  {
5969  rhs -= valscale * knapvals[i] * bestlbsol;
5970  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5971  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5972  }
5973  else
5974  {
5975  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5976  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5977  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5978 
5979  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5980  goto TERMINATE;
5981 
5982  if( !noknapsackconshdlr )
5983  {
5984  assert(tmpindices != NULL);
5985 
5986  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5987  ++tmp;
5988  }
5989  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5990  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5991  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5992  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5993  }
5994  }
5995  else
5996  {
5997  SCIP_VAR** zvub;
5998  SCIP_Real* bvub;
5999  SCIP_Real* dvub;
6000  SCIP_Real bestubsol;
6001  int bestubtype;
6002  int nvub;
6003  int j;
6004 
6005  assert(valscale * knapvals[i] < 0.0);
6006 
6007  /* a_j < 0: substitution with ub or vub */
6008  nvub = SCIPvarGetNVubs(var);
6009  zvub = SCIPvarGetVubVars(var);
6010  bvub = SCIPvarGetVubCoefs(var);
6011  dvub = SCIPvarGetVubConstants(var);
6012 
6013  /* search for ub or vub with minimal bound value */
6014  bestubsol = SCIPvarGetUbGlobal(var);
6015  bestubtype = -1;
6016  for( j = 0; j < nvub; j++ )
6017  {
6018  /* use only numerical stable vub with active binary variable z */
6019  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6020  {
6021  SCIP_Real vubsol;
6022 
6023  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6024  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6025  {
6026  *cutoff = TRUE;
6027  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6029  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6030  goto TERMINATE;
6031  }
6032 
6033  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6034  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6035  if( SCIPisLE(scip, vubsol, bestubsol) )
6036  {
6037  bestubsol = vubsol;
6038  bestubtype = j;
6039  }
6040  }
6041  }
6042 
6043  /* if no ub or vub with binary variable was found, we have to abort */
6044  if( SCIPisInfinity(scip, bestubsol) )
6045  goto TERMINATE;
6046 
6047  if( bestubtype == -1 )
6048  {
6049  rhs -= valscale * knapvals[i] * bestubsol;
6050  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6051  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6052  }
6053  else
6054  {
6055  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6056  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6057  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6058 
6059  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6060  goto TERMINATE;
6061 
6062  if( !noknapsackconshdlr )
6063  {
6064  assert(tmpindices != NULL);
6065 
6066  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6067  ++tmp;
6068  }
6069  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6070  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6071  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6072  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6073  }
6074  }
6075  }
6076 
6077  /* convert coefficients of all (now binary) variables to positive integers:
6078  * - make all coefficients integral
6079  * - make all coefficients positive (substitute negated variable)
6080  */
6081  nconsvars = 0;
6082 
6083  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6084  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6085  */
6087  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6088  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6089 
6090  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6091  if( !success )
6092  intscalar = 1.0;
6093 
6094  /* make all coefficients integral and positive:
6095  * - scale a~_j = a_j * intscalar
6096  * - substitute x~_j = 1 - x_j if a~_j < 0
6097  */
6098  rhs = rhs*intscalar;
6099 
6100  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6101  minact = 0;
6102  maxact = 0;
6103  for( i = 0; i < nbinvars; i++ )
6104  {
6105  SCIP_VAR* var;
6106  SCIP_Longint val;
6107 
6108  val = (SCIP_Longint)SCIPfloor(scip, binvals[i]*intscalar);
6109  if( val == 0 )
6110  continue;
6111 
6112  if( val > 0 )
6113  {
6114  var = binvars[i];
6115  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6116  val, SCIPvarGetName(var), binvals[i], rhs);
6117  }
6118  else
6119  {
6120  assert(val < 0);
6121 
6122  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6123  val = -val;
6124  rhs += val;
6125  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6126  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6127  }
6128 
6129  if( SCIPvarGetLbLocal(var) > 0.5 )
6130  minact += val;
6131  if( SCIPvarGetUbLocal(var) > 0.5 )
6132  maxact += val;
6133  consvals[nconsvars] = val;
6134  consvars[nconsvars] = var;
6135  nconsvars++;
6136  }
6137 
6138  if( nconsvars > 0 )
6139  {
6140  SCIP_Longint capacity;
6141 
6142  assert(consvars != NULL);
6143  assert(consvals != NULL);
6144  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6145 
6146 #ifdef SCIP_DEBUG
6147  {
6148  SCIP_Real act;
6149 
6150  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6151  act = 0.0;
6152  for( i = 0; i < nconsvars; ++i )
6153  {
6154  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6155  SCIPgetSolVal(scip, sol, consvars[i]));
6156  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6157  }
6158  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6159  capacity, rhs, act, minact, maxact);
6160  }
6161 #endif
6162 
6163  if( minact > capacity )
6164  {
6165  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6166  *cutoff = TRUE;
6167  goto TERMINATE;
6168  }
6169 
6170  if( maxact > capacity )
6171  {
6172  /* separate lifted cut from relaxed knapsack constraint */
6173  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6174  }
6175  }
6176 
6177  TERMINATE:
6178  /* free data structures */
6179  if( noknapsackconshdlr)
6180  {
6181  SCIPfreeBufferArray(scip, &binvals);
6182  }
6183  else
6184  {
6185  /* clear binvals */
6186  for( --tmp; tmp >= 0; --tmp)
6187  {
6188  assert(tmpindices != NULL);
6189  binvals[tmpindices[tmp]] = 0;
6190  }
6191  SCIPfreeBufferArray(scip, &tmpindices);
6192  }
6193  SCIPfreeBufferArray(scip, &consvals);
6194  SCIPfreeBufferArray(scip, &consvars);
6195 
6196  return SCIP_OKAY;
6197 }
6198 
6199 /** separates given knapsack constraint */
6200 static
6202  SCIP* scip, /**< SCIP data structure */
6203  SCIP_CONS* cons, /**< knapsack constraint */
6204  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6205  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6206  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6207  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6208  int* ncuts /**< pointer to add up the number of found cuts */
6209  )
6210 {
6211  SCIP_CONSDATA* consdata;
6212  SCIP_Bool violated;
6213 
6214  assert(ncuts != NULL);
6215  assert(cutoff != NULL);
6216  *cutoff = FALSE;
6217 
6218  consdata = SCIPconsGetData(cons);
6219  assert(consdata != NULL);
6220 
6221  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6222 
6223  /* check knapsack constraint itself for feasibility */
6224  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6225 
6226  if( violated )
6227  {
6228  /* add knapsack constraint as LP row to the LP */
6229  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6230  (*ncuts)++;
6231  }
6232  else if( sepacuts )
6233  {
6234  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6235  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6236  }
6237 
6238  return SCIP_OKAY;
6239 }
6240 
6241 /** adds coefficient to constraint data */
6242 static
6244  SCIP* scip, /**< SCIP data structure */
6245  SCIP_CONS* cons, /**< knapsack constraint */
6246  SCIP_VAR* var, /**< variable to add to knapsack */
6247  SCIP_Longint weight /**< weight of variable in knapsack */
6248  )
6249 {
6250  SCIP_CONSDATA* consdata;
6252  consdata = SCIPconsGetData(cons);
6253  assert(consdata != NULL);
6254  assert(SCIPvarIsBinary(var));
6255  assert(weight > 0);
6256 
6257  /* add the new coefficient to the LP row */
6258  if( consdata->row != NULL )
6259  {
6260  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6261  }
6262 
6263  /* check for fixed variable */
6264  if( SCIPvarGetLbGlobal(var) > 0.5 )
6265  {
6266  /* variable is fixed to one: reduce capacity */
6267  consdata->capacity -= weight;
6268  }
6269  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6270  {
6271  SCIP_Bool negated;
6272 
6273  /* get binary representative of variable */
6274  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6275 
6276  /* insert coefficient */
6277  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6278  consdata->vars[consdata->nvars] = var;
6279  consdata->weights[consdata->nvars] = weight;
6280  consdata->nvars++;
6281 
6282  /* capture variable */
6283  SCIP_CALL( SCIPcaptureVar(scip, var) );
6284 
6285  /* install the rounding locks of variable */
6286  SCIP_CALL( lockRounding(scip, cons, var) );
6287 
6288  /* catch events */
6289  if( SCIPconsIsTransformed(cons) )
6290  {
6291  SCIP_CONSHDLRDATA* conshdlrdata;
6292 
6293  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6294  assert(conshdlrdata != NULL);
6295  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6297  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6298  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6299 
6300  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6301  consdata->existmultaggr = TRUE;
6302 
6303  /* mark constraint to be propagated and presolved */
6304  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6305  consdata->presolvedtiming = 0;
6306  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6307  }
6308 
6309  /* update weight sums */
6310  updateWeightSums(consdata, var, weight);
6311 
6312  consdata->sorted = FALSE;
6313  consdata->cliquepartitioned = FALSE;
6314  consdata->negcliquepartitioned = FALSE;
6315  consdata->merged = FALSE;
6316  }
6317 
6318  return SCIP_OKAY;
6319 }
6320 
6321 /** deletes coefficient at given position from constraint data */
6322 static
6324  SCIP* scip, /**< SCIP data structure */
6325  SCIP_CONS* cons, /**< knapsack constraint */
6326  int pos /**< position of coefficient to delete */
6327  )
6328 {
6329  SCIP_CONSDATA* consdata;
6330  SCIP_VAR* var;
6332  consdata = SCIPconsGetData(cons);
6333  assert(consdata != NULL);
6334  assert(0 <= pos && pos < consdata->nvars);
6335 
6336  var = consdata->vars[pos];
6337  assert(var != NULL);
6338  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6339 
6340  /* delete the coefficient from the LP row */
6341  if( consdata->row != NULL )
6342  {
6343  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6344  }
6345 
6346  /* remove the rounding locks of variable */
6347  SCIP_CALL( unlockRounding(scip, cons, var) );
6348 
6349  /* drop events and mark constraint to be propagated and presolved */
6350  if( SCIPconsIsTransformed(cons) )
6351  {
6352  SCIP_CONSHDLRDATA* conshdlrdata;
6353 
6354  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6355  assert(conshdlrdata != NULL);
6357  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6358  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6359 
6360  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6361  consdata->presolvedtiming = 0;
6362  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6363  }
6364 
6365  /* decrease weight sums */
6366  updateWeightSums(consdata, var, -consdata->weights[pos]);
6367 
6368  /* move the last variable to the free slot */
6369  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6370  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6371  if( consdata->eventdata != NULL )
6372  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6373 
6374  /* release variable */
6375  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6376 
6377  /* try to use old clique partitions */
6378  if( consdata->cliquepartitioned )
6379  {
6380  assert(consdata->cliquepartition != NULL);
6381  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6382  * change the clique number */
6383  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6384  {
6385  int oldcliqenum;
6386 
6387  oldcliqenum = consdata->cliquepartition[pos];
6388  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6389 
6390  /* the following if and else cases assure that we have increasing clique numbers */
6391  if( consdata->cliquepartition[pos] > pos )
6392  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6393  else
6394  {
6395  int i;
6396  int cliquenumbefore;
6397 
6398  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6399  * occurs the same as the old one is still in the cliquepartition */
6400  if( oldcliqenum > consdata->cliquepartition[pos] )
6401  {
6402  for( i = 0; i < consdata->nvars; ++i )
6403  if( oldcliqenum == consdata->cliquepartition[i] )
6404  break;
6405  else if( oldcliqenum < consdata->cliquepartition[i] )
6406  {
6407  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6408  break;
6409  }
6410  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6411  * the biggest index, so decrease the number of cliques
6412  */
6413  if( i == consdata->nvars )
6414  --(consdata->ncliques);
6415  }
6416  /* if the old clique number was smaller than the new one we have to check the front for an element with
6417  * clique number minus 1 */
6418  else if( oldcliqenum < consdata->cliquepartition[pos] )
6419  {
6420  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6421  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6422 
6423  if( i < cliquenumbefore )
6424  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6425  }
6426  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6427  else if( pos == consdata->nvars - 1)
6428  {
6429  cliquenumbefore = consdata->cliquepartition[pos];
6430  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6431 
6432  if( i < cliquenumbefore )
6433  --(consdata->ncliques);
6434  }
6435  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6436  }
6437  }
6438  else
6439  --(consdata->ncliques);
6440  }
6441 
6442  if( consdata->negcliquepartitioned )
6443  {
6444  assert(consdata->negcliquepartition != NULL);
6445  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6446  * change the clique number */
6447  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6448  {
6449  int oldcliqenum;
6450 
6451  oldcliqenum = consdata->negcliquepartition[pos];
6452  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6453 
6454  /* the following if and else cases assure that we have increasing clique numbers */
6455  if( consdata->negcliquepartition[pos] > pos )
6456  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6457  else
6458  {
6459  int i;
6460  int cliquenumbefore;
6461 
6462  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6463  * occurs, the same as the old one occurs */
6464  if( oldcliqenum > consdata->negcliquepartition[pos] )
6465  {
6466  for( i = 0; i < consdata->nvars; ++i )
6467  if( oldcliqenum == consdata->negcliquepartition[i] )
6468  break;
6469  else if( oldcliqenum < consdata->negcliquepartition[i] )
6470  {
6471  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6472  break;
6473  }
6474  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6475  * the biggest index, so decrease the number of negated cliques
6476  */
6477  if( i == consdata->nvars )
6478  --(consdata->nnegcliques);
6479  }
6480  /* if the old clique number was smaller than the new one we have to check the front for an element with
6481  * clique number minus 1 */
6482  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6483  {
6484  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6485  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6486 
6487  if( i < cliquenumbefore )
6488  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6489  }
6490  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6491  else if( pos == consdata->nvars - 1)
6492  {
6493  cliquenumbefore = consdata->negcliquepartition[pos];
6494  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6495 
6496  if( i < cliquenumbefore )
6497  --(consdata->nnegcliques);
6498  }
6499  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6500  }
6501  }
6502  else
6503  --(consdata->nnegcliques);
6504  }
6505 
6506  --(consdata->nvars);
6507 
6508  return SCIP_OKAY;
6509 }
6510 
6511 /** removes all items with weight zero from knapsack constraint */
6512 static
6514  SCIP* scip, /**< SCIP data structure */
6515  SCIP_CONS* cons /**< knapsack constraint */
6516  )
6517 {
6518  SCIP_CONSDATA* consdata;
6519  int v;
6520 
6521  consdata = SCIPconsGetData(cons);
6522  assert(consdata != NULL);
6523 
6524  for( v = consdata->nvars-1; v >= 0; --v )
6525  {
6526  if( consdata->weights[v] == 0 )
6527  {
6528  SCIP_CALL( delCoefPos(scip, cons, v) );
6529  }
6530  }
6531 
6532  return SCIP_OKAY;
6533 }
6534 
6535 /* perform deletion of variables in all constraints of the constraint handler */
6536 static
6538  SCIP* scip, /**< SCIP data structure */
6539  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6540  SCIP_CONS** conss, /**< array of constraints */
6541  int nconss /**< number of constraints */
6542  )
6543 {
6544  SCIP_CONSDATA* consdata;
6545  int i;
6546  int v;
6547 
6548  assert(scip != NULL);
6549  assert(conshdlr != NULL);
6550  assert(conss != NULL);
6551  assert(nconss >= 0);
6552  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6553 
6554  /* iterate over all constraints */
6555  for( i = 0; i < nconss; i++ )
6556  {
6557  consdata = SCIPconsGetData(conss[i]);
6558 
6559  /* constraint is marked, that some of its variables were deleted */
6560  if( consdata->varsdeleted )
6561  {
6562  /* iterate over all variables of the constraint and delete them from the constraint */
6563  for( v = consdata->nvars - 1; v >= 0; --v )
6564  {
6565  if( SCIPvarIsDeleted(consdata->vars[v]) )
6566  {
6567  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6568  }
6569  }
6570  consdata->varsdeleted = FALSE;
6571  }
6572  }
6573 
6574  return SCIP_OKAY;
6575 }
6576 
6577 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6578 static
6580  SCIP* scip, /**< SCIP data structure */
6581  SCIP_CONS* cons, /**< knapsack constraint */
6582  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6583  )
6584 {
6585  SCIP_CONSDATA* consdata;
6586  int v;
6587  int prev;
6588 
6589  assert(scip != NULL);
6590  assert(cons != NULL);
6591  assert(cutoff != NULL);
6592 
6593  consdata = SCIPconsGetData(cons);
6594  assert(consdata != NULL);
6595 
6596  *cutoff = FALSE;
6597 
6598  if( consdata->merged )
6599  return SCIP_OKAY;
6600 
6601  if( consdata->nvars <= 1 )
6602  {
6603  consdata->merged = TRUE;
6604  return SCIP_OKAY;
6605  }
6606 
6607  assert(consdata->vars != NULL || consdata->nvars == 0);
6608 
6609  /* sorting array after indices of variables, that's only for faster merging */
6610  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6611  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6612 
6613  /* knapsack-sorting (decreasing weights) now lost */
6614  consdata->sorted = FALSE;
6615 
6616  v = consdata->nvars - 1;
6617  prev = v - 1;
6618  /* loop backwards through the items: deletion only affects rear items */
6619  while( prev >= 0 )
6620  {
6621  SCIP_VAR* var1;
6622  SCIP_VAR* var2;
6623  SCIP_Bool negated1;
6624  SCIP_Bool negated2;
6625 
6626  negated1 = FALSE;
6627  negated2 = FALSE;
6628 
6629  var1 = consdata->vars[v];
6630  assert(SCIPvarIsBinary(var1));
6631  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6633  {
6634  var1 = SCIPvarGetNegatedVar(var1);
6635  negated1 = TRUE;
6636  }
6637  assert(var1 != NULL);
6638 
6639  var2 = consdata->vars[prev];
6640  assert(SCIPvarIsBinary(var2));
6641  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6643  {
6644  var2 = SCIPvarGetNegatedVar(var2);
6645  negated2 = TRUE;
6646  }
6647  assert(var2 != NULL);
6648 
6649  if( var1 == var2 )
6650  {
6651  /* both variables are either active or negated */
6652  if( negated1 == negated2 )
6653  {
6654  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6655  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6656  SCIP_CALL( delCoefPos(scip, cons, v) );
6657  }
6658  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6659  * and delete item of smaller weight
6660  */
6661  else if( consdata->weights[v] == consdata->weights[prev] )
6662  {
6663  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6664  consdata->capacity -= consdata->weights[v];
6665  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6666  SCIP_CALL( delCoefPos(scip, cons, prev) );
6667 
6668  --prev;
6669  }
6670  else if( consdata->weights[v] < consdata->weights[prev] )
6671  {
6672  consdata->capacity -= consdata->weights[v];
6673  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6674  assert(consdata->weights[prev] > 0);
6675  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6676  }
6677  else
6678  {
6679  consdata->capacity -= consdata->weights[prev];
6680  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6681  assert(consdata->weights[v] > 0);
6682  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6683  /* restore order iff necessary */
6684  if( consdata->nvars != v ) /* otherwise the order still stands */
6685  {
6686  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6687  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6688  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6689  --prev;
6690  else /* we need to let v at the same position*/
6691  {
6692  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6693  /* don't decrease v, the same variable may exist up front */
6694  --prev;
6695  continue;
6696  }
6697  }
6698  }
6699  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6700  }
6701  v = prev;
6702  --prev;
6703  }
6704 
6705  consdata->merged = TRUE;
6706 
6707  /* check infeasibility */
6708  if( consdata->onesweightsum > consdata->capacity )
6709  {
6710  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6711  *cutoff = TRUE;
6712  return SCIP_OKAY;
6713  }
6714 
6715  return SCIP_OKAY;
6716 }
6717 
6718 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6719  * fixings (dual reductions)
6720  */
6721 static
6723  SCIP* scip, /**< SCIP data structure */
6724  SCIP_CONS* cons, /**< knapsack constraint */
6725  int* nfixedvars, /**< pointer to count number of fixings */
6726  int* ndelconss, /**< pointer to count number of deleted constraints */
6727  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6728  )
6729 {
6730  SCIP_CONSDATA* consdata;
6731  SCIP_VAR** vars;
6732  SCIP_Real* profits;
6733  int* solitems;
6734  int* nonsolitems;
6735  int* items;
6736  SCIP_Real solval;
6737  SCIP_Bool infeasible;
6738  SCIP_Bool tightened;
6739  SCIP_Bool applicable;
6740  int nsolitems;
6741  int nnonsolitems;
6742  int nvars;
6743  int v;
6744 
6745  assert(!SCIPconsIsModifiable(cons));
6746 
6747  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6748  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6749  * added to the problems have the check flag set to FALSE
6750  */
6751  if( !SCIPconsIsChecked(cons) )
6752  return SCIP_OKAY;
6753 
6754  consdata = SCIPconsGetData(cons);
6755  assert(consdata != NULL);
6756 
6757  nvars = consdata->nvars;
6758  vars = consdata->vars;
6759 
6760  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6761  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6762  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6763  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6764 
6765  applicable = TRUE;
6766 
6767  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6768  * collect object values which are the profits of the knapsack problem
6769  */
6770  for( v = 0; v < nvars; ++v )
6771  {
6772  SCIP_VAR* var;
6773  SCIP_Bool negated;
6774 
6775  var = vars[v];
6776  assert(var != NULL);
6777 
6778  /* the variable should not be (globally) fixed */
6779  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6780 
6783  {
6784  applicable = FALSE;
6785  break;
6786  }
6787 
6788  negated = FALSE;
6789 
6790  /* get the active variable */
6791  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6792  assert(SCIPvarIsActive(var));
6793 
6794  if( negated )
6795  profits[v] = SCIPvarGetObj(var);
6796  else
6797  profits[v] = -SCIPvarGetObj(var);
6798 
6799  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6800  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6801  items[v] = v;
6802  }
6803 
6804  if( applicable )
6805  {
6806  SCIP_Bool success;
6807 
6808  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6809  SCIPdebugPrintCons(scip, cons, NULL);
6810 
6811  /* solve knapsack problem exactly */
6812  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6813  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6814 
6815  if( success )
6816  {
6817  SCIP_VAR* var;
6818 
6819  /* apply solution of the knapsack as dual reductions */
6820  for( v = 0; v < nsolitems; ++v )
6821  {
6822  var = vars[solitems[v]];
6823  assert(var != NULL);
6824 
6825  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6827  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6828  assert(!infeasible);
6829  assert(tightened);
6830  (*nfixedvars)++;
6831  }
6832 
6833  for( v = 0; v < nnonsolitems; ++v )
6834  {
6835  var = vars[nonsolitems[v]];
6836  assert(var != NULL);
6837 
6838  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6840  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6841  assert(!infeasible);
6842  assert(tightened);
6843  (*nfixedvars)++;
6844  }
6845 
6846  SCIP_CALL( SCIPdelCons(scip, cons) );
6847  (*ndelconss)++;
6848  (*deleted) = TRUE;
6849  }
6850  }
6851 
6852  SCIPfreeBufferArray(scip, &nonsolitems);
6853  SCIPfreeBufferArray(scip, &solitems);
6854  SCIPfreeBufferArray(scip, &items);
6855  SCIPfreeBufferArray(scip, &profits);
6856 
6857  return SCIP_OKAY;
6858 }
6859 
6860 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6861  * constraint enters the LP by setting the initial and separated flag to FALSE
6862  */
6863 static
6865  SCIP* scip, /**< SCIP data structure */
6866  SCIP_CONS* cons, /**< knapsack constraint */
6867  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6868  )
6869 {
6870  SCIP_CONSDATA* consdata;
6871  SCIP_VAR** vars;
6872  SCIP_VAR* var;
6873  SCIP_Real offset;
6874  SCIP_Real scale;
6875  SCIP_Real objval;
6876  SCIP_Bool applicable;
6877  SCIP_Bool negated;
6878  int nobjvars;
6879  int nvars;
6880  int v;
6881 
6882  assert(scip != NULL);
6883  assert(cons != NULL);
6884  assert(conshdlrdata != NULL);
6885 
6886  consdata = SCIPconsGetData(cons);
6887  assert(consdata != NULL);
6888 
6889  nvars = consdata->nvars;
6890  nobjvars = SCIPgetNObjVars(scip);
6891 
6892  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6893  * and/or separated flag is set to FALSE
6894  */
6895  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6896  return SCIP_OKAY;
6897 
6898  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6899  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6900  */
6901  if( nobjvars == 0 )
6902  return SCIP_OKAY;
6903 
6904  vars = consdata->vars;
6905  assert(vars != NULL);
6906 
6907  applicable = TRUE;
6908  offset = 0.0;
6909  scale = 1.0;
6910 
6911  for( v = 0; v < nvars && applicable; ++v )
6912  {
6913  negated = FALSE;
6914  var = vars[v];
6915  assert(var != NULL);
6916 
6917  if( SCIPvarIsNegated(var) )
6918  {
6919  negated = TRUE;
6920  var = SCIPvarGetNegatedVar(var);
6921  assert(var != NULL);
6922  }
6923 
6924  objval = SCIPvarGetObj(var);
6925 
6926  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6927  if( SCIPisZero(scip, objval) )
6928  applicable = FALSE;
6929  else
6930  {
6931  SCIP_Real weight;
6932 
6933  weight = (SCIP_Real)consdata->weights[v];
6934 
6935  if( negated )
6936  {
6937  if( v == 0 )
6938  {
6939  /* the first variable defines the scale */
6940  scale = weight / -objval;
6941 
6942  offset += weight;
6943  }
6944  else if( SCIPisEQ(scip, -objval * scale, weight) )
6945  offset += weight;
6946  else
6947  applicable = FALSE;
6948  }
6949  else if( v == 0 )
6950  {
6951  /* the first variable define the scale */
6952  scale = weight / objval;
6953  }
6954  else if( !SCIPisEQ(scip, objval * scale, weight) )
6955  applicable = FALSE;
6956  }
6957  }
6958 
6959  if( applicable )
6960  {
6961  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6962  {
6963  SCIP_Real cutoffbound;
6964 
6965  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6966  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6967  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6968 
6969  cutoffbound = (consdata->capacity - offset) / scale;
6970 
6971  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6972  * still excepted
6973  */
6974  cutoffbound += SCIPcutoffbounddelta(scip);
6975 
6976  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6977  SCIPconsGetName(cons), cutoffbound);
6978 
6979  if( cutoffbound < SCIPgetCutoffbound(scip) )
6980  {
6981  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6982 
6983  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6984  }
6985  else
6986  {
6987  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6988  * propagation
6989  */
6990  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6991  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6992  }
6993  }
6994  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6995  {
6996  SCIP_Real lowerbound;
6997 
6998  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6999  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
7000  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
7001 
7002  lowerbound = (consdata->capacity - offset) / scale;
7003 
7004  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7005  SCIPconsGetName(cons), lowerbound);
7006 
7007  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
7008  }
7009  }
7010 
7011  return SCIP_OKAY;
7012 }
7013 
7014 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7015  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7016 static
7018  SCIP* scip, /**< SCIP data structure */
7019  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7020  SCIP_VAR** vars, /**< array for sorted variables */
7021  SCIP_Longint* weights, /**< array for sorted weights */
7022  int* cliquestartposs, /**< starting position array for each clique */
7023  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7024  )
7025 {
7026  SCIP_VAR** origvars;
7027  int norigvars;
7028  SCIP_Longint* origweights;
7029  int* cliquepartition;
7030  int ncliques;
7031 
7032  SCIP_VAR*** varpointers;
7033  SCIP_Longint** weightpointers;
7034  int* cliquecount;
7035 
7036  int nextpos;
7037  int c;
7038  int v;
7039 
7040  assert(scip != NULL);
7041  assert(consdata != NULL);
7042  assert(vars != NULL);
7043  assert(weights != NULL);
7044  assert(cliquestartposs != NULL);
7045 
7046  origweights = consdata->weights;
7047  origvars = consdata->vars;
7048  norigvars = consdata->nvars;
7049 
7050  assert(origvars != NULL || norigvars == 0);
7051  assert(origweights != NULL || norigvars == 0);
7052 
7053  if( norigvars == 0 )
7054  return SCIP_OKAY;
7055 
7056  if( usenegatedclique )
7057  {
7058  assert(consdata->negcliquepartitioned);
7059 
7060  cliquepartition = consdata->negcliquepartition;
7061  ncliques = consdata->nnegcliques;
7062  }
7063  else
7064  {
7065  assert(consdata->cliquepartitioned);
7066 
7067  cliquepartition = consdata->cliquepartition;
7068  ncliques = consdata->ncliques;
7069  }
7070 
7071  assert(cliquepartition != NULL);
7072  assert(ncliques > 0);
7073 
7074  /* we first count all clique items and alloc temporary memory for a bucket sort */
7075  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7076  BMSclearMemoryArray(cliquecount, ncliques);
7077 
7078  /* first we count for each clique the number of elements */
7079  for( v = norigvars - 1; v >= 0; --v )
7080  {
7081  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7082  ++(cliquecount[cliquepartition[v]]);
7083  }
7084 
7085  /*@todo: maybe it is better to put largest cliques up front */
7086 
7087 #ifndef NDEBUG
7088  BMSclearMemoryArray(vars, norigvars);
7089  BMSclearMemoryArray(weights, norigvars);
7090 #endif
7091  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7092  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7093 
7094  nextpos = 0;
7095  /* now we initialize all start pointers for each clique, so they will be ordered */
7096  for( c = 0; c < ncliques; ++c )
7097  {
7098  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7099  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7100  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7101  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7102  * vars[7]
7103  *
7104  */
7105  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7106  cliquestartposs[c] = nextpos;
7107  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7108  assert(cliquecount[c] > 0);
7109  nextpos += cliquecount[c];
7110  assert(nextpos > 0);
7111  }
7112  assert(nextpos == norigvars);
7113  cliquestartposs[c] = nextpos;
7114 
7115  /* now we copy all variable and weights to the right order */
7116  for( v = 0; v < norigvars; ++v )
7117  {
7118  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7119  ++(varpointers[cliquepartition[v]]);
7120  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7121  ++(weightpointers[cliquepartition[v]]);
7122  }
7123 #ifndef NDEBUG
7124  for( v = 0; v < norigvars; ++v )
7125  {
7126  assert(vars[v] != NULL);
7127  assert(weights[v] > 0);
7128  }
7129 #endif
7130 
7131  /* free temporary memory */
7132  SCIPfreeBufferArray(scip, &weightpointers);
7133  SCIPfreeBufferArray(scip, &varpointers);
7134  SCIPfreeBufferArray(scip, &cliquecount);
7135 
7136  return SCIP_OKAY;
7137 }
7138 
7139 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7140 static
7142  SCIP* scip, /**< SCIP data structure */
7143  SCIP_CONS* cons, /**< knapsack constraint */
7144  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7145  * information is not needed; in this case, we apply all fixings
7146  * instead of stopping after the first infeasible one */
7147  )
7148 {
7149  SCIP_CONSDATA* consdata;
7150  int v;
7151 
7152  assert(scip != NULL);
7153  assert(cons != NULL);
7154 
7155  consdata = SCIPconsGetData(cons);
7156  assert(consdata != NULL);
7157  assert(consdata->nvars == 0 || consdata->vars != NULL);
7158 
7159  if( cutoff != NULL )
7160  *cutoff = FALSE;
7161 
7162  SCIPdebugMsg(scip, "apply fixings:\n");
7163  SCIPdebugPrintCons(scip, cons, NULL);
7164 
7165  /* check infeasibility */
7166  if ( consdata->onesweightsum > consdata->capacity )
7167  {
7168  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7169 
7170  if( cutoff != NULL )
7171  *cutoff = TRUE;
7172 
7173  return SCIP_OKAY;
7174  }
7175 
7176  /* all multi-aggregations should be resolved */
7177  consdata->existmultaggr = FALSE;
7178 
7179  v = 0;
7180  while( v < consdata->nvars )
7181  {
7182  SCIP_VAR* var;
7183 
7184  var = consdata->vars[v];
7185  assert(SCIPvarIsBinary(var));
7186 
7187  if( SCIPvarGetLbGlobal(var) > 0.5 )
7188  {
7189  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7190  consdata->capacity -= consdata->weights[v];
7191  SCIP_CALL( delCoefPos(scip, cons, v) );
7192  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7193  }
7194  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7195  {
7196  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7197  SCIP_CALL( delCoefPos(scip, cons, v) );
7198  }
7199  else
7200  {
7201  SCIP_VAR* repvar;
7202  SCIP_VAR* negvar;
7203  SCIP_VAR* workvar;
7204  SCIP_Longint weight;
7205  SCIP_Bool negated;
7206 
7207  weight = consdata->weights[v];
7208 
7209  /* get binary representative of variable */
7210  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7211  assert(repvar != NULL);
7212 
7213  /* check for multi-aggregation */
7214  if( SCIPvarIsNegated(repvar) )
7215  {
7216  workvar = SCIPvarGetNegatedVar(repvar);
7217  assert(workvar != NULL);
7218  negated = TRUE;
7219  }
7220  else
7221  {
7222  workvar = repvar;
7223  negated = FALSE;
7224  }
7225 
7226  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7227  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7228  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7229  *
7230  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7231  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7232  *
7233  * The explanation for the following block:
7234  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7235  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7236  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7237  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7238  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7239  * 2) For all replacement variable we check:
7240  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7241  * capacity -= weight * a_i caused by the negation of y_i.
7242  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7243  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7244  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7245  * weight in this case.
7246  */
7247  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7248  {
7249  SCIP_VAR** aggrvars;
7250  SCIP_Real* aggrscalars;
7251  SCIP_Real aggrconst;
7252  int naggrvars;
7253  int i;
7254 
7255  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7256  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7257  aggrvars = SCIPvarGetMultaggrVars(workvar);
7258  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7259  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7260  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7261 
7262  if( !SCIPisIntegral(scip, weight * aggrconst) )
7263  {
7264  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7265  return SCIP_ERROR;
7266  }
7267 
7268  /* if workvar was negated, we have to flip the weight */
7269  if( negated )
7270  weight *= -1;
7271 
7272  for( i = naggrvars - 1; i >= 0; --i )
7273  {
7274  assert(aggrvars != NULL);
7275  assert(aggrscalars != NULL);
7276 
7277  if( !SCIPvarIsBinary(aggrvars[i]) )
7278  {
7279  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary variable <%s>\n", aggrvars[i]);
7280  return SCIP_ERROR;
7281  }
7282  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7283  {
7284  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7285  return SCIP_ERROR;
7286  }
7287  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7288  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7289  {
7290  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7291  assert(negvar != NULL);
7292  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7293  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7294  }
7295  else
7296  {
7297  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7298  }
7299  }
7300  /* delete old coefficient */
7301  SCIP_CALL( delCoefPos(scip, cons, v) );
7302 
7303  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7304  if( negated )
7305  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7306  else
7307  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7308 
7309  if( consdata->capacity < 0 )
7310  {
7311  if( cutoff != NULL )
7312  {
7313  *cutoff = TRUE;
7314  break;
7315  }
7316  }
7317  }
7318  /* check, if the variable should be replaced with the representative */
7319  else if( repvar != var )
7320  {
7321  /* delete old (aggregated) variable */
7322  SCIP_CALL( delCoefPos(scip, cons, v) );
7323 
7324  /* add representative instead */
7325  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7326  }
7327  else
7328  ++v;
7329  }
7330  }
7331  assert(consdata->onesweightsum == 0);
7332 
7333  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7334  SCIPdebugPrintCons(scip, cons, NULL);
7335 
7336  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7337  * clean up the constraint
7338  */
7339  if( cutoff != NULL && !(*cutoff) )
7340  {
7341  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7342  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7343  SCIPdebugPrintCons(scip, cons, NULL);
7344  }
7345 
7346  return SCIP_OKAY;
7347 }
7348 
7349 
7350 /** propagation method for knapsack constraints */
7351 static
7353  SCIP* scip, /**< SCIP data structure */
7354  SCIP_CONS* cons, /**< knapsack constraint */
7355  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7356  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7357  int* nfixedvars, /**< pointer to count number of fixings */
7358  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7359  )
7361  SCIP_CONSDATA* consdata;
7362  SCIP_Bool infeasible;
7363  SCIP_Bool tightened;
7364  SCIP_Longint* secondmaxweights;
7365  SCIP_Longint minweightsum;
7366  SCIP_Longint residualcapacity;
7367 
7368  int nvars;
7369  int i;
7370  int nnegcliques;
7371 
7372  SCIP_VAR** myvars;
7373  SCIP_Longint* myweights;
7374  int* cliquestartposs;
7375  int* cliqueendposs;
7376  SCIP_Longint localminweightsum;
7377  SCIP_Bool foundmax;
7378  int c;
7379 
7380  assert(scip != NULL);
7381  assert(cons != NULL);
7382  assert(cutoff != NULL);
7383  assert(redundant != NULL);
7384  assert(nfixedvars != NULL);
7385 
7386  consdata = SCIPconsGetData(cons);
7387  assert(consdata != NULL);
7388 
7389  *cutoff = FALSE;
7390  *redundant = FALSE;
7391 
7392  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7393 
7394  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7395  if( !SCIPinRepropagation(scip) )
7396  {
7397  SCIP_CALL( SCIPincConsAge(scip, cons) );
7398  }
7399 
7400 #ifndef NDEBUG
7401  /* assert that only active or negated variables are present */
7402  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7403  {
7404  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7405  }
7406 #endif
7407 
7408  usenegatedclique = usenegatedclique && consdata->merged;
7409 
7410  /* init for debugging */
7411  myvars = NULL;
7412  myweights = NULL;
7413  cliquestartposs = NULL;
7414  secondmaxweights = NULL;
7415  minweightsum = 0;
7416  nvars = consdata->nvars;
7417  /* make sure, the items are sorted by non-increasing weight */
7418  sortItems(consdata);
7419 
7420  do
7421  {
7422  localminweightsum = 0;
7423 
7424  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7425  * a negated clique means, that at most one of the clique variables can be zero
7426  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7427  *
7428  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7429  * since replacing i with the element of maximal weight leads to infeasibility
7430  */
7431  if( usenegatedclique && nvars > 0 )
7432  {
7433  SCIP_CONSHDLRDATA* conshdlrdata;
7434  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7435  assert(conshdlrdata != NULL);
7436 
7437  /* compute clique partitions */
7438  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7439  nnegcliques = consdata->nnegcliques;
7440 
7441  /* if we have no real negated cliques we can stop here */
7442  if( nnegcliques == nvars )
7443  {
7444  /* run the standard algorithm that does not involve cliques */
7445  usenegatedclique = FALSE;
7446  break;
7447  }
7448 
7449  /* allocate temporary memory and initialize it */
7450  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7451  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7452  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7453  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7454  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7455  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7456 
7457  /* resort variables to avoid quadratic algorithm later on */
7458  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7459 
7460  /* save the end positions of the cliques because start positions are moved in the following loop */
7461  for( c = 0; c < nnegcliques; ++c )
7462  {
7463  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7464  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7465  }
7466 
7467  c = 0;
7468  foundmax = FALSE;
7469  i = 0;
7470 
7471  while( i < nvars )
7472  {
7473  /* ignore variables of the negated clique which are fixed to one since these are counted in
7474  * consdata->onesweightsum
7475  */
7476 
7477  /* if there are only one variable negated cliques left we can stop */
7478  if( nnegcliques - c == nvars - i )
7479  {
7480  minweightsum += localminweightsum;
7481  localminweightsum = 0;
7482  break;
7483  }
7484 
7485  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7486  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7487  * other clique variables to one
7488  */
7489  if( cliquestartposs[c] == i )
7490  {
7491  assert(myweights[i] > 0);
7492  ++c;
7493  minweightsum += localminweightsum;
7494  localminweightsum = 0;
7495  foundmax = TRUE;
7496 
7497  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7498  foundmax = FALSE;
7499 
7500  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7501  {
7502  ++i;
7503  continue;
7504  }
7505  }
7506 
7507  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7508  {
7509  assert(myweights[i] > 0);
7510 
7511  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7512  {
7513  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7514 
7515  if( !foundmax )
7516  {
7517  foundmax = TRUE;
7518 
7519  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7520  cliquestartposs[c - 1] = i;
7521  ++i;
7522 
7523  continue;
7524  }
7525  /* memorize second max weight for each clique */
7526  if( secondmaxweights[c - 1] == 0 )
7527  secondmaxweights[c - 1] = myweights[i];
7528 
7529  localminweightsum += myweights[i];
7530  }
7531  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7532  else
7533  {
7534  int v;
7535  /* fix all other variables of the negated clique to 1 */
7536  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7537  {
7538  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7539  {
7540  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7541  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7542 
7543  if( infeasible )
7544  {
7545  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7546 
7547  /* analyze the infeasibility if conflict analysis is applicable */
7549  {
7550  /* conflict analysis can only be applied in solving stage */
7551  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7552 
7553  /* initialize the conflict analysis */
7555 
7556  /* add the two variables which are fixed to zero within a negated clique */
7557  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7558  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7559 
7560  /* start the conflict analysis */
7561  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7562  }
7563  *cutoff = TRUE;
7564  break;
7565  }
7566  assert(tightened);
7567  ++(*nfixedvars);
7568  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7569  }
7570  }
7571  if( *cutoff )
7572  break;
7573 
7574  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7575  localminweightsum = 0;
7576  /* we can jump to the end of this clique */
7577  i = cliqueendposs[c - 1];
7578  }
7579  }
7580  ++i;
7581  }
7582  /* add last clique minweightsum */
7583  minweightsum += localminweightsum;
7584 
7585  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7586  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7587 
7588  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7589  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7590  {
7591  SCIP_Longint maxcliqueweight = -1LL;
7592 
7593  /* loop over cliques */
7594  for( c = 0; c < nnegcliques; ++c )
7595  {
7596  SCIP_VAR* maxvar;
7597  SCIP_Bool maxvarfixed;
7598  int endvarposclique;
7599  int startvarposclique;
7600 
7601  assert(myvars != NULL);
7602  assert(nnegcliques == consdata->nnegcliques);
7603  assert(myweights != NULL);
7604  assert(secondmaxweights != NULL);
7605  assert(cliquestartposs != NULL);
7606 
7607  endvarposclique = cliqueendposs[c];
7608  startvarposclique = cliquestartposs[c];
7609 
7610  maxvar = myvars[startvarposclique];
7611 
7612  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7613  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7614  continue;
7615 
7616  maxcliqueweight = myweights[startvarposclique];
7617  maxvarfixed = FALSE;
7618  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7619  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7620  * exceeds the capacity the maximum weight variable can be fixed to zero.
7621  */
7622  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7623  {
7624 #ifndef NDEBUG
7625  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7626 #endif
7627  assert(maxcliqueweight >= secondmaxweights[c]);
7628  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7629 
7630  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7631  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7632  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7633  assert(consdata->onesweightsum == oldonesweightsum);
7634  assert(!infeasible);
7635  assert(tightened);
7636  (*nfixedvars)++;
7637  maxvarfixed = TRUE;
7638  }
7639  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7640  * fits into the knapsack
7641  */
7642  else if( nnegcliques - c == nvars - startvarposclique )
7643  break;
7644  /* early termination of the remaining loop because no further variable fixings are possible:
7645  *
7646  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7647  * largest was set to 0) does not suffice to infer additional variable fixings because
7648  *
7649  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7650  * - their second largest elements are at least as large as the smallest weight of the knapsack
7651  */
7652  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7653  break;
7654 
7655  /* loop over items with non-maximal weight (omitting the first position) */
7656  for( i = endvarposclique; i > startvarposclique; --i )
7657  {
7658  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7659  * messed up the clique preprocessing in the previous loop to filter those variables out */
7660  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7661 
7662  /* only check variables of negated cliques for which no variable is locally fixed */
7663  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7664  {
7665  assert(maxcliqueweight >= myweights[i]);
7666  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7667 
7668  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7669  *
7670  * the maxvar was already fixed to 0 because it has a huge gain.
7671  *
7672  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7673  * since replacing i with the element of maximal weight leads to infeasibility */
7674  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7675  {
7676 #ifndef NDEBUG
7677  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7678 #endif
7679  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7680  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7681  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7682  assert(!infeasible);
7683  assert(tightened);
7684  ++(*nfixedvars);
7685  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7686 
7687  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7688  * consdata->onesweightsum
7689  */
7690  minweightsum -= myweights[i];
7691  assert(minweightsum >= 0);
7692  }
7693  else
7694  break;
7695  }
7696  }
7697 #ifndef NDEBUG
7698  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7699  for( ; i > startvarposclique; --i )
7700  {
7701  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7702  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7703 
7704  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7705  assert(varisfixed || !exceedscapacity);
7706  }
7707 #endif
7708  }
7709  }
7710  SCIPfreeBufferArray(scip, &secondmaxweights);
7711  SCIPfreeBufferArray(scip, &cliqueendposs);
7712  SCIPfreeBufferArray(scip, &cliquestartposs);
7713  SCIPfreeBufferArray(scip, &myweights);
7714  SCIPfreeBufferArray(scip, &myvars);
7715  }
7716 
7717  assert(consdata->negcliquepartitioned || minweightsum == 0);
7718  }
7719  while( FALSE );
7720 
7721  assert(usenegatedclique || minweightsum == 0);
7722  /* check, if weights of fixed variables already exceed knapsack capacity */
7723  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7724  {
7725  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7726  consdata->onesweightsum, consdata->capacity);
7727 
7728  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7729  *cutoff = TRUE;
7730 
7731  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7733  {
7734  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7735  SCIP_Longint weight;
7736 
7737  weight = 0;
7738 
7740 
7741  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7742  {
7743  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7744  {
7745  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7746  weight += consdata->weights[i];
7747  }
7748  }
7749 
7750  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7751  }
7752 
7753  return SCIP_OKAY;
7754  }
7755 
7756  /* the algorithm below is a special case of propagation involving negated cliques */
7757  if( !usenegatedclique )
7758  {
7759  assert(consdata->sorted);
7760  residualcapacity = consdata->capacity - consdata->onesweightsum;
7761 
7762  /* fix all variables to zero, that don't fit into the knapsack anymore */
7763  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7764  {
7765  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7766  * to zero
7767  */
7768  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7769  {
7770  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7771  {
7772  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7773  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7774  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7775  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7776  assert(!infeasible);
7777  assert(tightened);
7778  (*nfixedvars)++;
7779  }
7780  }
7781  }
7782  }
7783 
7784  /* check if the knapsack is now redundant */
7785  if( !SCIPconsIsModifiable(cons) )
7786  {
7787  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7788 
7789  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7790  for( i = 0; i < nvars; ++i )
7791  {
7792  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7793  {
7794  unfixedweightsum += consdata->weights[i];
7795 
7796  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7797  if( unfixedweightsum > consdata->capacity )
7798  return SCIP_OKAY;
7799  }
7800  }
7801  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7802  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7803  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7804  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7805  *redundant = TRUE;
7806  }
7807 
7808  return SCIP_OKAY;
7809 }
7810 
7811 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7812  * containing all negated variables of this knapsack constraint
7813  */
7814 static
7816  SCIP* scip, /**< SCIP data structure */
7817  SCIP_CONS* cons, /**< knapsack constraint */
7818  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7819  int* naddconss /**< pointer to count number of added constraints */
7820  )
7821 {
7822  SCIP_CONS* newcons;
7823  SCIP_CONSDATA* consdata;
7824 
7825  assert(scip != NULL);
7826  assert(cons != NULL);
7827  assert(ndelconss != NULL);
7828  assert(naddconss != NULL);
7829 
7830  consdata = SCIPconsGetData(cons);
7831  assert(consdata != NULL);
7832  assert(consdata->nvars > 1);
7833 
7834  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7835  if( consdata->nvars == 2 )
7836  {
7837  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7838 
7839  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7843  SCIPconsIsStickingAtNode(cons)) );
7844  }
7845  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7846  * containing all negated variables of the knapsack
7847  */
7848  else
7849  {
7850  SCIP_VAR** consvars;
7851 
7852  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7853 
7854  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7855  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7856 
7857  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7861  SCIPconsIsStickingAtNode(cons)) );
7862 
7863  SCIPfreeBufferArray(scip, &consvars);
7864  }
7865 
7866  SCIP_CALL( SCIPaddCons(scip, newcons) );
7867  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7868  ++(*naddconss);
7869 
7870  SCIP_CALL( SCIPdelCons(scip, cons) );
7871  ++(*ndelconss);
7872 
7873  return SCIP_OKAY;
7874 }
7875 
7876 /** delete redundant variables
7877  *
7878  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7879  *
7880  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7881  * => x4, x5 always fits into the knapsack, so we can delete them
7882  *
7883  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7884  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7885  */
7886 static
7888  SCIP* scip, /**< SCIP data structure */
7889  SCIP_CONS* cons, /**< knapsack constraint */
7890  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7891  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7892  * first which did not fit */
7893  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7894  int* nchgsides, /**< pointer to store the amount of changed sides */
7895  int* naddconss /**< pointer to count number of added constraints */
7896  )
7897 {
7898  SCIP_CONSHDLRDATA* conshdlrdata;
7899  SCIP_CONSDATA* consdata;
7900  SCIP_VAR** vars;
7901  SCIP_Longint* weights;
7902  SCIP_Longint capacity;
7903  SCIP_Longint gcd;
7904  int nvars;
7905  int w;
7906 
7907  assert(scip != NULL);
7908  assert(cons != NULL);
7909  assert(nchgcoefs != NULL);
7910  assert(nchgsides != NULL);
7911  assert(naddconss != NULL);
7912 
7913  consdata = SCIPconsGetData(cons);
7914  assert(consdata != NULL);
7915  assert(0 < frontsum && frontsum < consdata->weightsum);
7916  assert(0 < splitpos && splitpos < consdata->nvars);
7917 
7918  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7919  assert(conshdlrdata != NULL);
7920 
7921  vars = consdata->vars;
7922  weights = consdata->weights;
7923  nvars = consdata->nvars;
7924  capacity = consdata->capacity;
7925 
7926  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7927  * weight must not be sorted by their index
7928  */
7929 #ifndef NDEBUG
7930  for( w = nvars - 1; w > 0; --w )
7931  assert(weights[w] <= weights[w-1]);
7932 #endif
7933 
7934  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7935  if( consdata->nvars - 1 == splitpos )
7936  return SCIP_OKAY;
7937 
7938  assert(frontsum + weights[splitpos] > capacity);
7939 
7940  /* detect redundant variables */
7941  if( consdata->weightsum - weights[splitpos] <= capacity )
7942  {
7943  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7944  * fit
7945  */
7946  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7947 
7948  /* delete items and update capacity */
7949  for( w = nvars - 1; w > splitpos; --w )
7950  {
7951  consdata->capacity -= weights[w];
7952  SCIP_CALL( delCoefPos(scip, cons, w) );
7953  }
7954  assert(w == splitpos);
7955 
7956  ++(*nchgsides);
7957  *nchgcoefs += (nvars - splitpos);
7958 
7959  /* division by greatest common divisor */
7960  gcd = weights[w];
7961  for( ; w >= 0 && gcd > 1; --w )
7962  {
7963  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7964  }
7965 
7966  /* normalize if possible */
7967  if( gcd > 1 )
7968  {
7969  for( w = splitpos; w >= 0; --w )
7970  {
7971  consdataChgWeight(consdata, w, weights[w]/gcd);
7972  }
7973  (*nchgcoefs) += nvars;
7974 
7975  consdata->capacity /= gcd;
7976  ++(*nchgsides);
7977  }
7978 
7979  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7980  * weight must not be sorted by their index
7981  */
7982 #ifndef NDEBUG
7983  for( w = consdata->nvars - 1; w > 0; --w )
7984  assert(weights[w] <= weights[w - 1]);
7985 #endif
7986  }
7987  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7988  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7989  * splitpos and needs to fit into the knapsack
7990  */
7991  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7992  {
7993  int* clqpart;
7994  int nclq;
7995  int len;
7996 
7997  len = nvars - (splitpos + 1);
7998  /* allocate temporary memory */
7999  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8000 
8001  /* calculate clique partition */
8002  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8003 
8004  /* check if we found at least one clique */
8005  if( nclq < len )
8006  {
8007  SCIP_Longint maxactduetoclq;
8008  int cliquenum;
8009 
8010  maxactduetoclq = 0;
8011  cliquenum = 0;
8012 
8013  /* calculate maximum activity due to cliques */
8014  for( w = 0; w < len; ++w )
8015  {
8016  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8017  if( clqpart[w] == cliquenum )
8018  {
8019  maxactduetoclq += weights[w + splitpos + 1];
8020  ++cliquenum;
8021  }
8022  }
8023 
8024  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8025  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8026  */
8027  if( frontsum + maxactduetoclq <= capacity )
8028  {
8029  SCIP_VAR** clqvars;
8030  int nclqvars;
8031  int c;
8032 
8033  assert(maxactduetoclq < weights[splitpos]);
8034 
8035  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8036 
8037  /* allocate temporary memory */
8038  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8039 
8040  for( c = 0; c < nclq; ++c )
8041  {
8042  nclqvars = 0;
8043  for( w = 0; w < len; ++w )
8044  {
8045  if( clqpart[w] == c )
8046  {
8047  clqvars[nclqvars] = vars[w + splitpos + 1];
8048  ++nclqvars;
8049  }
8050  }
8051 
8052  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8053  if( nclqvars > 1 )
8054  {
8055  SCIP_CONS* cliquecons;
8056  char name[SCIP_MAXSTRLEN];
8057 
8058  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8059  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8063  SCIPconsIsStickingAtNode(cons)) );
8064  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8065  SCIPdebugPrintCons(scip, cliquecons, NULL);
8066  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8067  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8068  ++(*naddconss);
8069  }
8070  }
8071 
8072  /* delete items and update capacity */
8073  for( w = nvars - 1; w > splitpos; --w )
8074  {
8075  SCIP_CALL( delCoefPos(scip, cons, w) );
8076  ++(*nchgcoefs);
8077  }
8078  consdata->capacity -= maxactduetoclq;
8079  assert(frontsum <= consdata->capacity);
8080  ++(*nchgsides);
8081 
8082  assert(w == splitpos);
8083 
8084  /* renew weights pointer */
8085  weights = consdata->weights;
8086 
8087  /* division by greatest common divisor */
8088  gcd = weights[w];
8089  for( ; w >= 0 && gcd > 1; --w )
8090  {
8091  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8092  }
8093 
8094  /* normalize if possible */
8095  if( gcd > 1 )
8096  {
8097  for( w = splitpos; w >= 0; --w )
8098  {
8099  consdataChgWeight(consdata, w, weights[w]/gcd);
8100  }
8101  (*nchgcoefs) += nvars;
8102 
8103  consdata->capacity /= gcd;
8104  ++(*nchgsides);
8105  }
8106 
8107  /* free temporary memory */
8108  SCIPfreeBufferArray(scip, &clqvars);
8109 
8110  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8111  * weight must not be sorted by their index
8112  */
8113 #ifndef NDEBUG
8114  for( w = consdata->nvars - 1; w > 0; --w )
8115  assert(weights[w] <= weights[w - 1]);
8116 #endif
8117  }
8118  }
8119 
8120  /* free temporary memory */
8121  SCIPfreeBufferArray(scip, &clqpart);
8122  }
8123 
8124  return SCIP_OKAY;
8125 }
8126 
8127 /* detect redundant variables which always fits into the knapsack
8128  *
8129  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8130  *
8131  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8132  * => x4, x5 always fits into the knapsack, so we can delete them
8133  *
8134  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8135  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8136  */
8137 static
8139  SCIP* scip, /**< SCIP data structure */
8140  SCIP_CONS* cons, /**< knapsack constraint */
8141  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8142  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8143  int* nchgsides, /**< pointer to store the amount of changed sides */
8144  int* naddconss /**< pointer to count number of added constraints */
8145  )
8147  SCIP_CONSHDLRDATA* conshdlrdata;
8148  SCIP_CONSDATA* consdata;
8149  SCIP_VAR** vars;
8150  SCIP_Longint* weights;
8151  SCIP_Longint capacity;
8152  SCIP_Longint sum;
8153  int noldchgcoefs;
8154  int nvars;
8155  int v;
8156  int w;
8157 
8158  assert(scip != NULL);
8159  assert(cons != NULL);
8160  assert(ndelconss != NULL);
8161  assert(nchgcoefs != NULL);
8162  assert(nchgsides != NULL);
8163  assert(naddconss != NULL);
8164 
8165  consdata = SCIPconsGetData(cons);
8166  assert(consdata != NULL);
8167  assert(consdata->nvars >= 2);
8168  assert(consdata->weightsum > consdata->capacity);
8169 
8170  noldchgcoefs = *nchgcoefs;
8171  vars = consdata->vars;
8172  weights = consdata->weights;
8173  nvars = consdata->nvars;
8174  capacity = consdata->capacity;
8175  sum = 0;
8176 
8177  /* search for maximal fitting items */
8178  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8179  sum += weights[v];
8180 
8181  assert(v < nvars);
8182 
8183  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8184  if( v == nvars - 1 )
8185  {
8186  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8187  assert(SCIPconsIsDeleted(cons));
8188 
8189  return SCIP_OKAY;
8190  }
8191 
8192  if( v < nvars - 1 )
8193  {
8194  /* try to delete variables */
8195  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8196  assert(consdata->nvars > 1);
8197 
8198  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8199  if( v == consdata->nvars - 1 )
8200  {
8201  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8202  assert(SCIPconsIsDeleted(cons));
8203  }
8204 
8205  return SCIP_OKAY;
8206  }
8207 
8208  /* if we already found some redundant variables, stop here */
8209  if( *nchgcoefs > noldchgcoefs )
8210  return SCIP_OKAY;
8211 
8212  assert(vars == consdata->vars);
8213  assert(weights == consdata->weights);
8214  assert(nvars == consdata->nvars);
8215  assert(capacity == consdata->capacity);
8216 
8217  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8218  assert(conshdlrdata != NULL);
8219  /* calculate clique partition */
8220  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8221 
8222  /* check for real existing cliques */
8223  if( consdata->cliquepartition[v] < v )
8224  {
8225  SCIP_Longint sumfront;
8226  SCIP_Longint maxactduetoclqfront;
8227  int* clqpart;
8228  int cliquenum;
8229 
8230  sumfront = 0;
8231  maxactduetoclqfront = 0;
8232 
8233  clqpart = consdata->cliquepartition;
8234  cliquenum = 0;
8235 
8236  /* calculate maximal activity due to cliques */
8237  for( w = 0; w < nvars; ++w )
8238  {
8239  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8240  if( clqpart[w] == cliquenum )
8241  {
8242  if( maxactduetoclqfront + weights[w] <= capacity )
8243  {
8244  maxactduetoclqfront += weights[w];
8245  ++cliquenum;
8246  }
8247  else
8248  break;
8249  }
8250  sumfront += weights[w];
8251  }
8252  assert(w >= v);
8253 
8254  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8255  * information
8256  */
8257  if( conshdlrdata->disaggregation && w == nvars )
8258  {
8259  SCIP_VAR** clqvars;
8260  int nclqvars;
8261  int c;
8262  int ncliques;
8263 
8264  assert(maxactduetoclqfront <= capacity);
8265 
8266  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8267 
8268  ncliques = consdata->ncliques;
8269 
8270  /* allocate temporary memory */
8271  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8272 
8273  for( c = 0; c < ncliques; ++c )
8274  {
8275  nclqvars = 0;
8276  for( w = 0; w < nvars; ++w )
8277  {
8278  if( clqpart[w] == c )
8279  {
8280  clqvars[nclqvars] = vars[w];
8281  ++nclqvars;
8282  }
8283  }
8284 
8285  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8286  if( nclqvars > 1 )
8287  {
8288  SCIP_CONS* cliquecons;
8289  char name[SCIP_MAXSTRLEN];
8290 
8291  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8292  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8296  SCIPconsIsStickingAtNode(cons)) );
8297  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8298  SCIPdebugPrintCons(scip, cliquecons, NULL);
8299  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8300  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8301  ++(*naddconss);
8302  }
8303  }
8304 
8305  /* delete old constraint */
8306  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8307  ++(*ndelconss);
8308 
8309  SCIPfreeBufferArray(scip, &clqvars);
8310 
8311  return SCIP_OKAY;
8312  }
8313 
8314  if( w > v && w < nvars - 1 )
8315  {
8316  /* try to delete variables */
8317  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8318  }
8319  }
8320 
8321  return SCIP_OKAY;
8322 }
8323 
8324 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8325 static
8326 void normalizeWeights(
8327  SCIP_CONS* cons, /**< knapsack constraint */
8328  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8329  int* nchgsides /**< pointer to count number of side changes */
8330  )
8331 {
8332  SCIP_CONSDATA* consdata;
8333  SCIP_Longint gcd;
8334  int i;
8335 
8336  assert(nchgcoefs != NULL);
8337  assert(nchgsides != NULL);
8338  assert(!SCIPconsIsModifiable(cons));
8339 
8340  consdata = SCIPconsGetData(cons);
8341  assert(consdata != NULL);
8342  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8343  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8344  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8345  assert(consdata->nvars >= 1);
8346 
8347  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8348  sortItems(consdata);
8349 
8350  gcd = consdata->weights[consdata->nvars-1];
8351  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8352  {
8353  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8354  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8355 
8356  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8357  }
8358 
8359  if( gcd >= 2 )
8360  {
8361  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8362 
8363  for( i = 0; i < consdata->nvars; ++i )
8364  {
8365  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8366  }
8367  consdata->capacity /= gcd;
8368  (*nchgcoefs) += consdata->nvars;
8369  (*nchgsides)++;
8370 
8371  /* weight should still be sorted, because the reduction preserves this */
8372 #ifndef NDEBUG
8373  for( i = consdata->nvars - 1; i > 0; --i )
8374  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8375 #endif
8376  consdata->sorted = TRUE;
8377  }
8378 }
8379 
8380 /** dual weights tightening for knapsack constraints
8381  *
8382  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8383  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8384  * constraint
8385  *
8386  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8387  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8388  *
8389  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8390  *
8391  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8392  *
8393  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8394  *
8395  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8396  *
8397  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8398  */
8399 static
8401  SCIP* scip, /**< SCIP data structure */
8402  SCIP_CONS* cons, /**< knapsack constraint */
8403  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8404  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8405  int* nchgsides, /**< pointer to store the amount of changed sides */
8406  int* naddconss /**< pointer to count number of added constraints */
8407  )
8409  SCIP_CONSDATA* consdata;
8410  SCIP_Longint* weights;
8411  SCIP_Longint dualcapacity;
8412  SCIP_Longint reductionsum;
8413  SCIP_Longint capacity;
8414  SCIP_Longint exceedsum;
8415  int oldnchgcoefs;
8416  int nvars;
8417  int vbig;
8418  int v;
8419  int w;
8420 #ifndef NDEBUG
8421  int oldnchgsides;
8422 #endif
8423 
8424  assert(scip != NULL);
8425  assert(cons != NULL);
8426  assert(ndelconss != NULL);
8427  assert(nchgcoefs != NULL);
8428  assert(nchgsides != NULL);
8429  assert(naddconss != NULL);
8430 
8431 #ifndef NDEBUG
8432  oldnchgsides = *nchgsides;
8433 #endif
8434 
8435  consdata = SCIPconsGetData(cons);
8436  assert(consdata != NULL);
8437  assert(consdata->weightsum > consdata->capacity);
8438  assert(consdata->nvars >= 2);
8439  assert(consdata->sorted);
8440 
8441  /* constraint should be merged */
8442  assert(consdata->merged);
8443 
8444  nvars = consdata->nvars;
8445  weights = consdata->weights;
8446  capacity = consdata->capacity;
8447 
8448  oldnchgcoefs = *nchgcoefs;
8449 
8450  /* case 1. */
8451  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8452  {
8453  SCIP_CONS* newcons;
8454 
8455  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8456  *
8457  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8458  */
8459  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8460 
8461  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8465  SCIPconsIsStickingAtNode(cons)) );
8466 
8467  SCIP_CALL( SCIPaddCons(scip, newcons) );
8468  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8469  ++(*naddconss);
8470 
8471  SCIP_CALL( SCIPdelCons(scip, cons) );
8472  ++(*ndelconss);
8473 
8474  return SCIP_OKAY;
8475  }
8476 
8477  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8478  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8479  {
8480  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8481  assert(SCIPconsIsDeleted(cons));
8482 
8483  return SCIP_OKAY;
8484  }
8485 
8486  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8487  /* @todo might be changed/removed when improving the coeffcients tightening */
8488  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8489  return SCIP_OKAY;
8490 
8491  /* case 2. */
8492 
8493  v = 0;
8494 
8495  /* @todo generalize the following algorithm for several parts of the knapsack
8496  *
8497  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8498  * variables each combination is a minimal cover, some examples
8499  *
8500  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8501  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8502  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8503  *
8504  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8505  *
8506  */
8507 
8508  /* determine big weights that fit only by itself */
8509  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8510  ++v;
8511 
8512  vbig = v;
8513  assert(vbig < nvars - 1);
8514  exceedsum = 0;
8515 
8516  /* determine the amount needed to exceed the capacity */
8517  while( v < nvars && exceedsum <= capacity )
8518  {
8519  exceedsum += weights[v];
8520  ++v;
8521  }
8522 
8523  /* if we exceeded the capacity we might reduce the weights */
8524  if( exceedsum > capacity )
8525  {
8526  assert(vbig > 0 || v < nvars);
8527 
8528  /* all small weights were needed to exceed the capacity */
8529  if( v == nvars )
8530  {
8531  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8532  assert(newweight > 0);
8533 
8534  /* reduce big weights */
8535  for( v = 0; v < vbig; ++v )
8536  {
8537  if( weights[v] > newweight )
8538  {
8539  consdataChgWeight(consdata, v, newweight);
8540  ++(*nchgcoefs);
8541  }
8542  }
8543 
8544  /* reduce small weights */
8545  for( ; v < nvars; ++v )
8546  {
8547  if( weights[v] > 1 )
8548  {
8549  consdataChgWeight(consdata, v, 1LL);
8550  ++(*nchgcoefs);
8551  }
8552  }
8553 
8554  consdata->capacity = newweight;
8555 
8556  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8557  * weight must not be sorted by their index
8558  */
8559 #ifndef NDEBUG
8560  for( v = nvars - 1; v > 0; --v )
8561  assert(weights[v] <= weights[v-1]);
8562 #endif
8563 
8564  return SCIP_OKAY;
8565  }
8566  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8567  * small weights
8568  */
8569  else
8570  {
8571  SCIP_Longint exceedsumback = 0;
8572  int nexceed = v - vbig;
8573 
8574  assert(nexceed > 1);
8575 
8576  /* determine weightsum of the same amount as before but of the smallest weight */
8577  for( w = nvars - 1; w >= nvars - nexceed; --w )
8578  exceedsumback += weights[w];
8579 
8580  assert(w >= 0);
8581 
8582  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8583  * combinations of all small weights
8584  */
8585  if( exceedsumback > capacity )
8586  {
8587  SCIP_Longint newweight = nexceed - 1;
8588 
8589  /* taking out the smallest element needs to fit */
8590  assert(exceedsumback - weights[nvars - 1] <= capacity);
8591 
8592  /* reduce big weights */
8593  for( v = 0; v < vbig; ++v )
8594  {
8595  if( weights[v] > newweight )
8596  {
8597  consdataChgWeight(consdata, v, newweight);
8598  ++(*nchgcoefs);
8599  }
8600  }
8601 
8602  /* reduce small weights */
8603  for( ; v < nvars; ++v )
8604  {
8605  if( weights[v] > 1 )
8606  {
8607  consdataChgWeight(consdata, v, 1LL);
8608  ++(*nchgcoefs);
8609  }
8610  }
8611 
8612  consdata->capacity = newweight;
8613 
8614  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8615  * weight must not be sorted by their index
8616  */
8617 #ifndef NDEBUG
8618  for( v = nvars - 1; v > 0; --v )
8619  assert(weights[v] <= weights[v-1]);
8620 #endif
8621  return SCIP_OKAY;
8622  }
8623  }
8624  }
8625  else
8626  {
8627  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8628  * not happen here
8629  */
8630  assert(vbig > 0 && vbig < nvars);
8631 
8632  /* either choose a big coefficients or all other variables
8633  *
8634  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8635  *
8636  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8637  * constraint to
8638  *
8639  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8640  */
8641 
8642  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8643  {
8644  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8645 #ifndef NDEBUG
8646  SCIP_Longint resweightsum = consdata->weightsum;
8647 
8648  for( v = 0; v < vbig; ++v )
8649  resweightsum -= weights[v];
8650 
8651  assert(exceedsum == resweightsum);
8652 #endif
8653  assert(newweight > 0);
8654 
8655  /* reduce big weights */
8656  for( v = 0; v < vbig; ++v )
8657  {
8658  if( weights[v] > newweight )
8659  {
8660  consdataChgWeight(consdata, v, newweight);
8661  ++(*nchgcoefs);
8662  }
8663  }
8664 
8665  /* reduce small weights */
8666  for( ; v < nvars; ++v )
8667  {
8668  if( weights[v] > 1 )
8669  {
8670  consdataChgWeight(consdata, v, 1LL);
8671  ++(*nchgcoefs);
8672  }
8673  }
8674 
8675  consdata->capacity = newweight;
8676 
8677  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8678  * weight must not be sorted by their index
8679  */
8680 #ifndef NDEBUG
8681  for( v = nvars - 1; v > 0; --v )
8682  assert(weights[v] <= weights[v-1]);
8683 #endif
8684  return SCIP_OKAY;
8685  }
8686  }
8687 
8688  /* case 3. */
8689 
8690  dualcapacity = consdata->weightsum - capacity;
8691  reductionsum = 0;
8692  v = 0;
8693 
8694  /* reduce big weights
8695  *
8696  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8697  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8698  * <=> x0 + x1 + x2 + x3 <= 3
8699  */
8700  while( weights[v] > dualcapacity )
8701  {
8702  reductionsum += (weights[v] - dualcapacity);
8703  consdataChgWeight(consdata, v, dualcapacity);
8704  ++v;
8705  assert(v < nvars);
8706  }
8707  (*nchgcoefs) += v;
8708 
8709  /* skip weights equal to the dualcapacity, because we cannot change them */
8710  while( v < nvars && weights[v] == dualcapacity )
8711  ++v;
8712 
8713  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8714  * after a possible removal of the last, redundant item
8715  *
8716  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8717  */
8718  if( v >= nvars - 1 )
8719  {
8720  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8721  if( v == nvars - 1 )
8722  {
8723  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8724  }
8725  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8726  assert(SCIPconsIsDeleted(cons));
8727 
8728  return SCIP_OKAY;
8729  }
8730  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8731  {
8732  /* @todo generalize the following algorithm for more than two variables */
8733 
8734  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8735  {
8736  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8737  * coefficients) of all or two variables of the rest
8738  *
8739  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8740  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8741  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8742  *
8743  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8744  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8745  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8746  *
8747  */
8748  if( v > 0 && weights[nvars - 2] > 1 )
8749  {
8750  int ncoefchg = 0;
8751 
8752  /* reduce all bigger weights */
8753  for( w = 0; w < v; ++w )
8754  {
8755  if( weights[w] > 2 )
8756  {
8757  consdataChgWeight(consdata, w, 2LL);
8758  ++ncoefchg;
8759  }
8760  else
8761  {
8762  assert(weights[0] == 2);
8763  assert(weights[v - 1] == 2);
8764  break;
8765  }
8766  }
8767 
8768  /* reduce all smaller weights */
8769  for( w = v; w < nvars; ++w )
8770  {
8771  if( weights[w] > 1 )
8772  {
8773  consdataChgWeight(consdata, w, 1LL);
8774  ++ncoefchg;
8775  }
8776  }
8777  assert(ncoefchg > 0);
8778 
8779  (*nchgcoefs) += ncoefchg;
8780 
8781  /* correct the capacity */
8782  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8783  assert(consdata->capacity > 0);
8784  assert(weights[0] <= consdata->capacity);
8785  assert(consdata->weightsum > consdata->capacity);
8786  /* reset the reductionsum */
8787  reductionsum = 0;
8788  }
8789  else if( v == 0 )
8790  {
8791  assert(weights[nvars - 2] == 1);
8792  }
8793  }
8794  else
8795  {
8796  SCIP_Longint minweight = weights[nvars - 1];
8797  SCIP_Longint newweight = dualcapacity - minweight;
8798  SCIP_Longint restsumweights = 0;
8799  SCIP_Longint sumcoef;
8800  SCIP_Bool sumcoefcase = FALSE;
8801  int startv = v;
8802  int end;
8803  int k;
8804 
8805  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8806 
8807  /* reduce big weights of pairs that exceed the dualcapacity
8808  *
8809  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8810  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8811  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8812  */
8813  while( weights[v] > newweight )
8814  {
8815  reductionsum += (weights[v] - newweight);
8816  consdataChgWeight(consdata, v, newweight);
8817  ++v;
8818  assert(v < nvars);
8819  }
8820  (*nchgcoefs) += (v - startv);
8821 
8822  /* skip equal weights */
8823  while( weights[v] == newweight )
8824  ++v;
8825 
8826  if( v > 0 )
8827  {
8828  for( w = v; w < nvars; ++w )
8829  restsumweights += weights[w];
8830  }
8831  else
8832  restsumweights = consdata->weightsum;
8833 
8834  if( restsumweights < dualcapacity )
8835  {
8836  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8837  *
8838  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8839  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8840  */
8841  if( startv == v )
8842  {
8843  /* remove redundant variables */
8844  for( w = nvars - 1; w >= v; --w )
8845  {
8846  SCIP_CALL( delCoefPos(scip, cons, v) );
8847  ++(*nchgcoefs);
8848  }
8849 
8850 #ifndef NDEBUG
8851  /* each coefficients should exceed the dualcapacity by itself */
8852  for( ; w >= 0; --w )
8853  assert(weights[w] == dualcapacity);
8854 #endif
8855  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8856  * upgrade this constraint
8857  */
8858  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8859  assert(SCIPconsIsDeleted(cons));
8860 
8861  return SCIP_OKAY;
8862  }
8863 
8864  /* special case where we have three different coefficient types
8865  *
8866  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8867  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8868  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8869  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8870  */
8871  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8872  {
8873  SCIP_Longint newcap;
8874 
8875  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8876  for( w = nvars - 1; w >= v; --w )
8877  {
8878  if( weights[w] > 1 )
8879  {
8880  consdataChgWeight(consdata, w, 1LL);
8881  ++(*nchgcoefs);
8882  }
8883  }
8884 
8885  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8886  * dualcapacity
8887  */
8888  newweight = (SCIP_Longint)nvars - v;
8889  assert(newweight > 1);
8890  for( ; w >= startv; --w )
8891  {
8892  if( weights[w] > newweight )
8893  {
8894  consdataChgWeight(consdata, w, newweight);
8895  ++(*nchgcoefs);
8896  }
8897  else
8898  assert(weights[w] == newweight);
8899  }
8900 
8901  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8902  ++newweight;
8903  assert(newweight > 2);
8904  for( ; w >= 0; --w )
8905  {
8906  if( weights[w] > newweight )
8907  {
8908  consdataChgWeight(consdata, w, newweight);
8909  ++(*nchgcoefs);
8910  }
8911  else
8912  assert(weights[w] == newweight);
8913  }
8914 
8915  /* update the capacity */
8916  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8917  if( consdata->capacity > newcap )
8918  {
8919  consdata->capacity = newcap;
8920  ++(*nchgsides);
8921  }
8922  else
8923  assert(consdata->capacity == newcap);
8924  }
8925  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8926 
8927  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8928  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8929 
8930  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8931  * weight must not be sorted by their index
8932  */
8933 #ifndef NDEBUG
8934  for( w = nvars - 1; w > 0; --w )
8935  assert(weights[w] <= weights[w - 1]);
8936 #endif
8937  return SCIP_OKAY;
8938  }
8939 
8940  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8941  end = nvars - 2;
8942  while( end >= 0 && weights[end] == weights[end + 1] )
8943  {
8944  assert(end >= v);
8945  --end;
8946  }
8947 
8948  if( v >= end )
8949  goto TERMINATE;
8950 
8951  end = nvars - 2;
8952 
8953  /* can we stop early, another special reduction case might exist */
8954  if( 2 * weights[end] > dualcapacity )
8955  {
8956  restsumweights = 0;
8957 
8958  /* determine capacity of the small items */
8959  for( w = end + 1; w < nvars; ++w )
8960  restsumweights += weights[w];
8961 
8962  if( restsumweights * 2 <= dualcapacity )
8963  {
8964  /* check for further posssible reductions in the middle */
8965  while( v < end && restsumweights + weights[v] >= dualcapacity )
8966  ++v;
8967 
8968  if( v >= end )
8969  goto TERMINATE;
8970 
8971  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8972  if( (dualcapacity & 1) == 0 )
8973  {
8974  newweight = dualcapacity / 2;
8975 
8976  /* set all middle coefficients */
8977  for( ; v <= end; ++v )
8978  {
8979  if( weights[v] > newweight )
8980  {
8981  reductionsum += (weights[v] - newweight);
8982  consdataChgWeight(consdata, v, newweight);
8983  ++(*nchgcoefs);
8984  }
8985  }
8986  }
8987  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8988  * other coefficients by 2
8989  */
8990  else
8991  {
8992  /* correct the reductionsum */
8993  reductionsum *= 2;
8994 
8995  /* multiply big coefficients by 2 */
8996  for( w = 0; w < v; ++w )
8997  {
8998  consdataChgWeight(consdata, w, weights[w] * 2);
8999  }
9000 
9001  newweight = dualcapacity;
9002  /* set all middle coefficients */
9003  for( ; v <= end; ++v )
9004  {
9005  reductionsum += (2 * weights[v] - newweight);
9006  consdataChgWeight(consdata, v, newweight);
9007  }
9008 
9009  /* multiply small coefficients by 2 */
9010  for( w = end + 1; w < nvars; ++w )
9011  {
9012  consdataChgWeight(consdata, w, weights[w] * 2);
9013  }
9014  (*nchgcoefs) += nvars;
9015 
9016  dualcapacity *= 2;
9017  consdata->capacity *= 2;
9018  ++(*nchgsides);
9019  }
9020  }
9021 
9022  goto TERMINATE;
9023  }
9024 
9025  /* further reductions using the next possible coefficient sum
9026  *
9027  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9028  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9029  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9030  */
9031  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9032  for( k = 0; k < 4; ++k )
9033  {
9034  /* determine next minimal coefficient sum */
9035  switch( k )
9036  {
9037  case 0:
9038  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9039  break;
9040  case 1:
9041  assert(nvars >= 3);
9042  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9043  break;
9044  case 2:
9045  assert(nvars >= 4);
9046  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9047  {
9048  sumcoefcase = TRUE;
9049  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9050  }
9051  else
9052  {
9053  sumcoefcase = FALSE;
9054  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9055  }
9056  break;
9057  case 3:
9058  assert(nvars >= 5);
9059  if( sumcoefcase )
9060  {
9061  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9062  }
9063  else
9064  {
9065  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9066  }
9067  break;
9068  default:
9069  return SCIP_ERROR;
9070  }
9071 
9072  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9073  minweight = weights[end];
9074  while( minweight <= sumcoef )
9075  {
9076  newweight = dualcapacity - minweight;
9077  startv = v;
9078  assert(v < nvars);
9079 
9080  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9081  /* shrink big coefficients */
9082  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9083  {
9084  reductionsum += (weights[v] - newweight);
9085  consdataChgWeight(consdata, v, newweight);
9086  ++v;
9087  assert(v < nvars);
9088  }
9089  (*nchgcoefs) += (v - startv);
9090 
9091  /* skip unchangable weights */
9092  while( weights[v] + minweight == dualcapacity )
9093  {
9094  assert(v < nvars);
9095  ++v;
9096  }
9097 
9098  --end;
9099  /* skip same end weights */
9100  while( end >= 0 && weights[end] == weights[end + 1] )
9101  --end;
9102 
9103  if( v >= end )
9104  goto TERMINATE;
9105 
9106  minweight = weights[end];
9107  }
9108 
9109  if( v >= end )
9110  goto TERMINATE;
9111 
9112  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9113  if( sumcoef < minweight )
9114  {
9115  minweight = sumcoef;
9116  newweight = dualcapacity - minweight;
9117  startv = v;
9118  assert(v < nvars);
9119 
9120  /* shrink big coefficients */
9121  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9122  {
9123  reductionsum += (weights[v] - newweight);
9124  consdataChgWeight(consdata, v, newweight);
9125  ++v;
9126  assert(v < nvars);
9127  }
9128  (*nchgcoefs) += (v - startv);
9129 
9130  /* skip unchangable weights */
9131  while( weights[v] + minweight == dualcapacity )
9132  {
9133  assert(v < nvars);
9134  ++v;
9135  }
9136  }
9137 
9138  if( v >= end )
9139  goto TERMINATE;
9140 
9141  /* can we stop early, another special reduction case might exist */
9142  if( 2 * weights[end] > dualcapacity )
9143  {
9144  restsumweights = 0;
9145 
9146  /* determine capacity of the small items */
9147  for( w = end + 1; w < nvars; ++w )
9148  restsumweights += weights[w];
9149 
9150  if( restsumweights * 2 <= dualcapacity )
9151  {
9152  /* check for further posssible reductions in the middle */
9153  while( v < end && restsumweights + weights[v] >= dualcapacity )
9154  ++v;
9155 
9156  if( v >= end )
9157  goto TERMINATE;
9158 
9159  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9160  if( (dualcapacity & 1) == 0 )
9161  {
9162  newweight = dualcapacity / 2;
9163 
9164  /* set all middle coefficients */
9165  for( ; v <= end; ++v )
9166  {
9167  if( weights[v] > newweight )
9168  {
9169  reductionsum += (weights[v] - newweight);
9170  consdataChgWeight(consdata, v, newweight);
9171  ++(*nchgcoefs);
9172  }
9173  }
9174  }
9175  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9176  * other coefficients by 2
9177  */
9178  else
9179  {
9180  /* correct the reductionsum */
9181  reductionsum *= 2;
9182 
9183  /* multiply big coefficients by 2 */
9184  for( w = 0; w < v; ++w )
9185  {
9186  consdataChgWeight(consdata, w, weights[w] * 2);
9187  }
9188 
9189  newweight = dualcapacity;
9190  /* set all middle coefficients */
9191  for( ; v <= end; ++v )
9192  {
9193  reductionsum += (2 * weights[v] - newweight);
9194  consdataChgWeight(consdata, v, newweight);
9195  }
9196 
9197  /* multiply small coefficients by 2 */
9198  for( w = end + 1; w < nvars; ++w )
9199  {
9200  consdataChgWeight(consdata, w, weights[w] * 2);
9201  }
9202  (*nchgcoefs) += nvars;
9203 
9204  dualcapacity *= 2;
9205  consdata->capacity *= 2;
9206  ++(*nchgsides);
9207  }
9208  }
9209 
9210  goto TERMINATE;
9211  }
9212 
9213  /* cannot tighten any further */
9214  if( 2 * sumcoef > dualcapacity )
9215  goto TERMINATE;
9216  }
9217  }
9218  }
9219 
9220  TERMINATE:
9221  /* correct capacity */
9222  if( reductionsum > 0 )
9223  {
9224  assert(v > 0);
9225 
9226  consdata->capacity -= reductionsum;
9227  ++(*nchgsides);
9228 
9229  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9230  }
9231  assert(weights[0] <= consdata->capacity);
9232 
9233  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9234  * weight must not be sorted by their index
9235  */
9236 #ifndef NDEBUG
9237  for( w = nvars - 1; w > 0; --w )
9238  assert(weights[w] <= weights[w - 1]);
9239 #endif
9240 
9241  if( oldnchgcoefs < *nchgcoefs )
9242  {
9243  assert(!SCIPconsIsDeleted(cons));
9244 
9245  /* it might be that we can divide the weights by their greatest common divisor */
9246  normalizeWeights(cons, nchgcoefs, nchgsides);
9247  }
9248  else
9249  {
9250  assert(oldnchgcoefs == *nchgcoefs);
9251  assert(oldnchgsides == *nchgsides);
9252  }
9253 
9254  return SCIP_OKAY;
9255 }
9256 
9257 
9258 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9259 static
9261  SCIP* scip, /**< SCIP data structure */
9262  SCIP_CONS* cons, /**< knapsack constraint */
9263  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9264  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9265  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9266  )
9267 {
9268  SCIP_VAR** vars;
9269  SCIP_CONSDATA* consdata;
9270  SCIP_Longint* weights;
9271  SCIP_Longint capacity;
9272  SCIP_Bool infeasible;
9273  SCIP_Bool fixed;
9274  int nvars;
9275  int v;
9276 
9277  assert(scip != NULL);
9278  assert(cons != NULL);
9279  assert(nfixedvars != NULL);
9280  assert(ndelconss != NULL);
9281  assert(nchgcoefs != NULL);
9282 
9283  consdata = SCIPconsGetData(cons);
9284  assert(consdata != NULL);
9285 
9286  nvars = consdata->nvars;
9287 
9288  /* no variables left, then delete constraint */
9289  if( nvars == 0 )
9290  {
9291  assert(consdata->capacity >= 0);
9292 
9293  SCIP_CALL( SCIPdelCons(scip, cons) );
9294  ++(*ndelconss);
9295 
9296  return SCIP_OKAY;
9297  }
9298 
9299  /* sort items */
9300  sortItems(consdata);
9301 
9302  vars = consdata->vars;
9303  weights = consdata->weights;
9304  capacity = consdata->capacity;
9305  v = 0;
9306 
9307  /* check for weights bigger than the capacity */
9308  while( v < nvars && weights[v] > capacity )
9309  {
9310  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9311  assert(!infeasible);
9312 
9313  if( fixed )
9314  ++(*nfixedvars);
9315 
9316  ++v;
9317  }
9318 
9319  /* if we fixed at least one variable we need to delete them from the constraint */
9320  if( v > 0 )
9321  {
9322  if( v == nvars )
9323  {
9324  SCIP_CALL( SCIPdelCons(scip, cons) );
9325  ++(*ndelconss);
9326 
9327  return SCIP_OKAY;
9328  }
9329 
9330  /* delete all position from back to front */
9331  for( --v; v >= 0; --v )
9332  {
9333  SCIP_CALL( delCoefPos(scip, cons, v) );
9334  ++(*nchgcoefs);
9335  }
9336 
9337  /* sort items again because of deletion */
9338  sortItems(consdata);
9339  assert(vars == consdata->vars);
9340  assert(weights == consdata->weights);
9341  }
9342  assert(consdata->sorted);
9343  assert(weights[0] <= capacity);
9344 
9345  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9346  {
9347  SCIP_CALL( SCIPdelCons(scip, cons) );
9348  ++(*ndelconss);
9349  }
9350 
9351  return SCIP_OKAY;
9352 }
9353 
9354 
9355 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9356  *
9357  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9358  *
9359  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9360  *
9361  * the above constraint can be changed to
9362  *
9363  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9364  *
9365  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9366  *
9367  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9368  *
9369  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9370  * constraint further, e.g.
9371  *
9372  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9373  * => 2x1 + x2 + x3 + x4 <= 2
9374  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9375  */
9376 static
9378  SCIP* scip, /**< SCIP data structure */
9379  SCIP_CONS* cons, /**< knapsack constraint */
9380  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9381  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9382  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9383  int* nchgsides, /**< pointer to store the amount of changed sides */
9384  int* naddconss, /**< pointer to count number of added constraints */
9385  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9386  )
9387 {
9388  SCIP_VAR** vars;
9389  SCIP_CONSDATA* consdata;
9390  SCIP_Longint* weights;
9391  SCIP_Longint restweight;
9392  SCIP_Longint newweight;
9393  SCIP_Longint weight;
9394  SCIP_Longint oldgcd;
9395  SCIP_Longint rest;
9396  SCIP_Longint gcd;
9397  int oldnchgcoefs;
9398  int oldnchgsides;
9399  int candpos;
9400  int candpos2;
9401  int offsetv;
9402  int nvars;
9403  int v;
9404 
9405  assert(scip != NULL);
9406  assert(cons != NULL);
9407  assert(nfixedvars != NULL);
9408  assert(ndelconss != NULL);
9409  assert(nchgcoefs != NULL);
9410  assert(nchgsides != NULL);
9411  assert(naddconss != NULL);
9412  assert(cutoff != NULL);
9413  assert(!SCIPconsIsModifiable(cons));
9414 
9415  consdata = SCIPconsGetData(cons);
9416  assert( consdata != NULL );
9417 
9418  *cutoff = FALSE;
9419 
9420  /* remove double enties and also combinations of active and negated variables */
9421  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9422  assert(consdata->merged);
9423  if( *cutoff )
9424  return SCIP_OKAY;
9425 
9426  assert(consdata->capacity >= 0);
9427 
9428  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9429  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9430 
9431  if( SCIPconsIsDeleted(cons) )
9432  return SCIP_OKAY;
9433 
9434  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9435  {
9436  /* 1. dual weights tightening */
9437  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9438 
9439  if( SCIPconsIsDeleted(cons) )
9440  return SCIP_OKAY;
9441  /* 2. delete redundant variables */
9442  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9443 
9444  if( SCIPconsIsDeleted(cons) )
9445  return SCIP_OKAY;
9446  }
9447 
9448  weights = consdata->weights;
9449  nvars = consdata->nvars;
9450 
9451 #ifndef NDEBUG
9452  /* constraint might not be sorted, but the weights are already sorted */
9453  for( v = nvars - 1; v > 0; --v )
9454  assert(weights[v] <= weights[v-1]);
9455 #endif
9456 
9457  /* determine greatest common divisor */
9458  gcd = weights[nvars - 1];
9459  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9460  {
9461  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9462  }
9463 
9464  /* divide the constraint by their greatest common divisor */
9465  if( gcd >= 2 )
9466  {
9467  for( v = nvars - 1; v >= 0; --v )
9468  {
9469  consdataChgWeight(consdata, v, weights[v]/gcd);
9470  }
9471  (*nchgcoefs) += nvars;
9472 
9473  consdata->capacity /= gcd;
9474  (*nchgsides)++;
9475  }
9476  assert(consdata->nvars == nvars);
9477 
9478  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9479  * must not be sorted by their index
9480  */
9481 #ifndef NDEBUG
9482  for( v = nvars - 1; v > 0; --v )
9483  assert(weights[v] <= weights[v-1]);
9484 #endif
9485 
9486  /* 3. start gcd procedure for all variables */
9487  do
9488  {
9489  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9490  SCIPdebug( oldnchgsides = *nchgsides; )
9491 
9492  vars = consdata->vars;
9493  weights = consdata->weights;
9494  nvars = consdata->nvars;
9495 
9496  /* stop if we have two coefficients which are one in absolute value */
9497  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9498  return SCIP_OKAY;
9499 
9500  v = 0;
9501  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9502  * gcd
9503  */
9504  while( weights[v] == consdata->capacity )
9505  {
9506  ++v;
9507  assert(v < nvars);
9508  }
9509 
9510  /* all but one variable are as big as the capacity, this is handled elsewhere */
9511  if( v == nvars - 1 )
9512  return SCIP_OKAY;
9513 
9514  offsetv = v;
9515 
9516  gcd = -1;
9517  candpos = -1;
9518  candpos2 = -1;
9519 
9520  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9521  * change the coefficient
9522  */
9523  for( v = nvars - 1; v >= offsetv; --v )
9524  {
9525  weight = weights[v];
9526  assert(weight >= 1);
9527 
9528  oldgcd = gcd;
9529 
9530  if( gcd == -1 )
9531  {
9532  gcd = weights[v];
9533  assert(gcd >= 1);
9534  }
9535  else
9536  {
9537  /* calculate greatest common divisor for all variables */
9538  gcd = SCIPcalcGreComDiv(gcd, weight);
9539  }
9540 
9541  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9542  * can terminate
9543  */
9544  if( gcd == 1 )
9545  {
9546  /* found candidate */
9547  if( candpos == -1 )
9548  {
9549  gcd = oldgcd;
9550  candpos = v;
9551 
9552  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9553  if( v == nvars - 2 )
9554  candpos2 = v + 1;
9555  }
9556  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9557  else
9558  {
9559  if( candpos == v + 1 && candpos2 == v + 2 )
9560  {
9561  assert(candpos2 == nvars - 1);
9562 
9563  /* take new candidates */
9564  candpos = candpos2;
9565 
9566  /* recalculate gcd from scratch */
9567  gcd = weights[v+1];
9568  assert(gcd >= 1);
9569 
9570  /* calculate greatest common divisor for variables */
9571  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9572  if( gcd == 1 )
9573  return SCIP_OKAY;
9574  }
9575  else
9576  /* cannot determine a possible coefficient for reduction */
9577  return SCIP_OKAY;
9578  }
9579  }
9580  }
9581  assert(gcd >= 2);
9582 
9583  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9584  * further
9585  */
9586  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9587 
9588  /* determine the remainder of the capacity and the gcd */
9589  rest = consdata->capacity % gcd;
9590  assert(rest >= 0);
9591  assert(rest < gcd);
9592 
9593  if( candpos == -1 )
9594  {
9595  /* we assume that the constraint was normalized */
9596  assert(rest > 0);
9597 
9598  /* replace old with new capacity */
9599  consdata->capacity -= rest;
9600  ++(*nchgsides);
9601 
9602  /* replace old big coefficients with new capacity */
9603  for( v = 0; v < offsetv; ++v )
9604  {
9605  consdataChgWeight(consdata, v, consdata->capacity);
9606  }
9607 
9608  *nchgcoefs += offsetv;
9609  goto CONTINUE;
9610  }
9611 
9612  /* determine the remainder of the coefficient candidate and the gcd */
9613  restweight = weights[candpos] % gcd;
9614  assert(restweight >= 1);
9615  assert(restweight < gcd);
9616 
9617  /* calculate new coefficient */
9618  if( restweight > rest )
9619  newweight = weights[candpos] - restweight + gcd;
9620  else
9621  newweight = weights[candpos] - restweight;
9622 
9623  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9624 
9625  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);
9626 
9627  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9628  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9629  */
9630  if( newweight == 0 && offsetv > 0 )
9631  return SCIP_OKAY;
9632 
9633  if( rest > 0 )
9634  {
9635  /* replace old with new capacity */
9636  consdata->capacity -= rest;
9637  ++(*nchgsides);
9638 
9639  /* replace old big coefficients with new capacity */
9640  for( v = 0; v < offsetv; ++v )
9641  {
9642  consdataChgWeight(consdata, v, consdata->capacity);
9643  }
9644 
9645  *nchgcoefs += offsetv;
9646  }
9647 
9648  if( newweight == 0 )
9649  {
9650  /* delete redundant coefficient */
9651  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9652  assert(consdata->nvars == nvars - 1);
9653  --nvars;
9654  }
9655  else
9656  {
9657  /* replace old with new coefficient */
9658  consdataChgWeight(consdata, candpos, newweight);
9659  }
9660  ++(*nchgcoefs);
9661 
9662  assert(consdata->vars == vars);
9663  assert(consdata->nvars == nvars);
9664  assert(consdata->weights == weights);
9665 
9666  CONTINUE:
9667  /* now constraint can be normalized, dividing it by the gcd */
9668  for( v = nvars - 1; v >= 0; --v )
9669  {
9670  consdataChgWeight(consdata, v, weights[v]/gcd);
9671  }
9672  (*nchgcoefs) += nvars;
9673 
9674  consdata->capacity /= gcd;
9675  ++(*nchgsides);
9676 
9677  SCIPdebugPrintCons(scip, cons, NULL);
9678 
9679  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));
9680  }
9681  while( nvars >= 2 );
9682 
9683  return SCIP_OKAY;
9684 }
9685 
9686 
9687 /** inserts an element into the list of binary zero implications */
9688 static
9690  SCIP* scip, /**< SCIP data structure */
9691  int** liftcands, /**< array of the lifting candidates */
9692  int* nliftcands, /**< number of lifting candidates */
9693  int** firstidxs, /**< array of first zeroitems indices */
9694  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9695  int** zeroitems, /**< pointer to zero items array */
9696  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9697  int* zeroitemssize, /**< pointer to size of zero items array */
9698  int* nzeroitems, /**< pointer to length of zero items array */
9699  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9700  SCIP_Bool value, /**< value v of variable y in implication */
9701  int knapsackidx, /**< index of variable x in knapsack */
9702  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9703  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9704  )
9705 {
9706  int nzeros;
9707 
9708  assert(liftcands != NULL);
9709  assert(liftcands[value] != NULL);
9710  assert(nliftcands != NULL);
9711  assert(firstidxs != NULL);
9712  assert(firstidxs[value] != NULL);
9713  assert(zeroweightsums != NULL);
9714  assert(zeroweightsums[value] != NULL);
9715  assert(zeroitems != NULL);
9716  assert(nextidxs != NULL);
9717  assert(zeroitemssize != NULL);
9718  assert(nzeroitems != NULL);
9719  assert(*nzeroitems <= *zeroitemssize);
9720  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9721  assert(memlimitreached != NULL);
9722 
9723  nzeros = *nzeroitems;
9724 
9725  /* allocate enough memory */
9726  if( nzeros == *zeroitemssize )
9727  {
9728  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9729  * this can be too huge - abort on memory limit
9730  */
9731  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9732  {
9733  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9734  *zeroitemssize);
9735  *memlimitreached = TRUE;
9736  return SCIP_OKAY;
9737  }
9738  *zeroitemssize *= 2;
9739  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9740  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9741  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9742  }
9743  assert(nzeros < *zeroitemssize);
9744 
9745  if( *memlimitreached )
9746  *memlimitreached = FALSE;
9747 
9748  /* insert element */
9749  (*zeroitems)[nzeros] = knapsackidx;
9750  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9751  if( firstidxs[value][probindex] == 0 )
9752  {
9753  liftcands[value][nliftcands[value]] = probindex;
9754  ++nliftcands[value];
9755  }
9756  firstidxs[value][probindex] = nzeros;
9757  ++(*nzeroitems);
9758  zeroweightsums[value][probindex] += knapsackweight;
9759 
9760  return SCIP_OKAY;
9761 }
9762 
9763 #define MAX_CLIQUELENGTH 50
9764 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9765  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9766  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9767  * if cliqueweightsum(xi == v) < capacity:
9768  * - fixing variable xi to v would make the knapsack constraint redundant
9769  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9770  * redundancy effect:
9771  * wi' := capacity - cliqueweightsum(xi == v)
9772  * this rule can also be applied to binary variables not in the knapsack!
9773  */
9774 static
9776  SCIP* scip, /**< SCIP data structure */
9777  SCIP_CONS* cons, /**< knapsack constraint */
9778  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9779  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9780  )
9781 {
9782  SCIP_CONSDATA* consdata;
9783  SCIP_VAR** binvars;
9784  int nbinvars;
9785  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9786  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9787  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9788  int* zeroitems; /* item number in knapsack that is implied to zero */
9789  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9790  int zeroitemssize;
9791  int nzeroitems;
9792  SCIP_Bool* zeroiteminserted[2];
9793  SCIP_Bool memlimitreached;
9794  int nliftcands[2];
9795  SCIP_Bool* cliqueused;
9796  SCIP_Bool* itemremoved;
9797  SCIP_Longint maxcliqueweightsum;
9798  SCIP_VAR** addvars;
9799  SCIP_Longint* addweights;
9800  SCIP_Longint addweightsum;
9801  int nvars;
9802  int cliquenum;
9803  int naddvars;
9804  int val;
9805  int i;
9806 
9807  int* tmpindices;
9808  SCIP_Bool* tmpboolindices;
9809  int* tmpindices2;
9810  SCIP_Bool* tmpboolindices2;
9811  int* tmpindices3;
9812  SCIP_Bool* tmpboolindices3;
9813  int tmp;
9814  int tmp2;
9815  int tmp3;
9816  SCIP_CONSHDLR* conshdlr;
9817  SCIP_CONSHDLRDATA* conshdlrdata;
9818 
9819  assert(nchgcoefs != NULL);
9820  assert(!SCIPconsIsModifiable(cons));
9821 
9822  consdata = SCIPconsGetData(cons);
9823  assert(consdata != NULL);
9824  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9825  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9826  assert(consdata->nvars > 0);
9827  assert(consdata->merged);
9828 
9829  nvars = consdata->nvars;
9830 
9831  /* check if the knapsack has too many items/cliques for applying this costly method */
9832  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9833  return SCIP_OKAY;
9834 
9835  /* sort items, s.t. the heaviest one is in the first position */
9836  sortItems(consdata);
9837 
9838  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9839  return SCIP_OKAY;
9840 
9841  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9842  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9843  assert(nbinvars > 0);
9844  binvars = SCIPgetVars(scip);
9845 
9846  /* get conshdlrdata to use cleared memory */
9847  conshdlr = SCIPconsGetHdlr(cons);
9848  assert(conshdlr != NULL);
9849  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9850  assert(conshdlrdata != NULL);
9851 
9852  /* allocate temporary memory for the list of implied to zero variables */
9853  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9854  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9855  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9856 
9857  assert(conshdlrdata->ints1size > 0);
9858  assert(conshdlrdata->ints2size > 0);
9859  assert(conshdlrdata->longints1size > 0);
9860  assert(conshdlrdata->longints2size > 0);
9861 
9862  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9863  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9864  * transform all integers into their binary representation then it maybe happens
9865  */
9866  if( conshdlrdata->ints1size < nbinvars )
9867  {
9868  int oldsize = conshdlrdata->ints1size;
9869 
9870  conshdlrdata->ints1size = nbinvars;
9871  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9872  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9873  }
9874  if( conshdlrdata->ints2size < nbinvars )
9875  {
9876  int oldsize = conshdlrdata->ints2size;
9877 
9878  conshdlrdata->ints2size = nbinvars;
9879  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9880  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9881  }
9882  if( conshdlrdata->longints1size < nbinvars )
9883  {
9884  int oldsize = conshdlrdata->longints1size;
9885 
9886  conshdlrdata->longints1size = nbinvars;
9887  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9888  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9889  }
9890  if( conshdlrdata->longints2size < nbinvars )
9891  {
9892  int oldsize = conshdlrdata->longints2size;
9893 
9894  conshdlrdata->longints2size = nbinvars;
9895  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9896  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9897  }
9898 
9899  firstidxs[0] = conshdlrdata->ints1;
9900  firstidxs[1] = conshdlrdata->ints2;
9901  zeroweightsums[0] = conshdlrdata->longints1;
9902  zeroweightsums[1] = conshdlrdata->longints2;
9903 
9904  /* check for cleared arrays, all entries are zero */
9905 #ifndef NDEBUG
9906  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9907  {
9908  assert(firstidxs[0][tmp] == 0);
9909  assert(firstidxs[1][tmp] == 0);
9910  assert(zeroweightsums[0][tmp] == 0);
9911  assert(zeroweightsums[1][tmp] == 0);
9912  }
9913 #endif
9914 
9915  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9916  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9917 
9918  zeroitems[0] = -1; /* dummy element */
9919  nextidxs[0] = -1;
9920  nzeroitems = 1;
9921  nliftcands[0] = 0;
9922  nliftcands[1] = 0;
9923 
9924  assert(conshdlrdata->bools1size > 0);
9925  assert(conshdlrdata->bools2size > 0);
9926 
9927  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9928  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9929  * transform all integers into their binary representation then it maybe happens
9930  */
9931  if( conshdlrdata->bools1size < nbinvars )
9932  {
9933  int oldsize = conshdlrdata->bools1size;
9934 
9935  conshdlrdata->bools1size = nbinvars;
9936  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9937  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9938  }
9939  if( conshdlrdata->bools2size < nbinvars )
9940  {
9941  int oldsize = conshdlrdata->bools2size;
9942 
9943  conshdlrdata->bools2size = nbinvars;
9944  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9945  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9946  }
9947 
9948  zeroiteminserted[0] = conshdlrdata->bools1;
9949  zeroiteminserted[1] = conshdlrdata->bools2;
9950 
9951  /* check for cleared arrays, all entries are zero */
9952 #ifndef NDEBUG
9953  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9954  {
9955  assert(zeroiteminserted[0][tmp] == 0);
9956  assert(zeroiteminserted[1][tmp] == 0);
9957  }
9958 #endif
9959 
9960  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9961  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9962  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9963  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9964  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9965  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9966  tmp2 = 0;
9967  tmp3 = 0;
9968 
9969  memlimitreached = FALSE;
9970  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9971  {
9972  SCIP_CLIQUE** cliques;
9973  SCIP_VAR* var;
9974  SCIP_Longint weight;
9975  SCIP_Bool value;
9976  int varprobindex;
9977  int ncliques;
9978  int j;
9979 
9980  tmp = 0;
9981 
9982  /* get corresponding active problem variable */
9983  var = consdata->vars[i];
9984  weight = consdata->weights[i];
9985  value = TRUE;
9986  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9987  varprobindex = SCIPvarGetProbindex(var);
9988  assert(0 <= varprobindex && varprobindex < nbinvars);
9989 
9990  /* update the zeroweightsum */
9991  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9992  tmpboolindices3[tmp3] = !value;
9993  tmpindices3[tmp3] = varprobindex;
9994  ++tmp3;
9995 
9996  /* initialize the arrays of inserted zero items */
9997  /* first add the implications (~x == 1 -> x == 0) */
9998  {
9999  SCIP_Bool implvalue;
10000  int probindex;
10001 
10002  probindex = SCIPvarGetProbindex(var);
10003  assert(0 <= probindex && probindex < nbinvars);
10004 
10005  implvalue = !value;
10006 
10007  /* insert the item into the list of the implied variable/value */
10008  assert( !zeroiteminserted[implvalue][probindex] );
10009 
10010  if( firstidxs[implvalue][probindex] == 0 )
10011  {
10012  tmpboolindices2[tmp2] = implvalue;
10013  tmpindices2[tmp2] = probindex;
10014  ++tmp2;
10015  }
10016  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10017  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10018  &memlimitreached) );
10019  zeroiteminserted[implvalue][probindex] = TRUE;
10020  tmpboolindices[tmp] = implvalue;
10021  tmpindices[tmp] = probindex;
10022  ++tmp;
10023  }
10024 
10025  /* get the cliques where the knapsack item is member of with value 1 */
10026  ncliques = SCIPvarGetNCliques(var, value);
10027  cliques = SCIPvarGetCliques(var, value);
10028  for( j = 0; j < ncliques && !memlimitreached; ++j )
10029  {
10030  SCIP_VAR** cliquevars;
10031  SCIP_Bool* cliquevalues;
10032  int ncliquevars;
10033  int k;
10034 
10035  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10036 
10037  /* discard big cliques */
10038  if( ncliquevars > MAX_CLIQUELENGTH )
10039  continue;
10040 
10041  cliquevars = SCIPcliqueGetVars(cliques[j]);
10042  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10043 
10044  for( k = ncliquevars - 1; k >= 0; --k )
10045  {
10046  SCIP_Bool implvalue;
10047  int probindex;
10048 
10049  if( var == cliquevars[k] )
10050  continue;
10051 
10052  probindex = SCIPvarGetProbindex(cliquevars[k]);
10053  if( probindex == -1 )
10054  continue;
10055 
10056  assert(0 <= probindex && probindex < nbinvars);
10057  implvalue = cliquevalues[k];
10058 
10059  /* insert the item into the list of the clique variable/value */
10060  if( !zeroiteminserted[implvalue][probindex] )
10061  {
10062  if( firstidxs[implvalue][probindex] == 0 )
10063  {
10064  tmpboolindices2[tmp2] = implvalue;
10065  tmpindices2[tmp2] = probindex;
10066  ++tmp2;
10067  }
10068 
10069  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10070  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10071  &memlimitreached) );
10072  zeroiteminserted[implvalue][probindex] = TRUE;
10073  tmpboolindices[tmp] = implvalue;
10074  tmpindices[tmp] = probindex;
10075  ++tmp;
10076 
10077  if( memlimitreached )
10078  break;
10079  }
10080  }
10081  }
10082  /* clear zeroiteminserted */
10083  for( --tmp; tmp >= 0; --tmp)
10084  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10085  }
10086  SCIPfreeBufferArray(scip, &tmpboolindices);
10087 
10088  /* calculate the clique partition and the maximal sum of weights using the clique information */
10089  assert(consdata->sorted);
10090  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10091 
10092  assert(conshdlrdata->bools3size > 0);
10093 
10094  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10095  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10096  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10097  */
10098  if( conshdlrdata->bools3size < consdata->nvars )
10099  {
10100  int oldsize = conshdlrdata->bools3size;
10101 
10102  conshdlrdata->bools3size = consdata->nvars;;
10103  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10104  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10105  }
10106 
10107  cliqueused = conshdlrdata->bools3;
10108 
10109  /* check for cleared array, all entries are zero */
10110 #ifndef NDEBUG
10111  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10112  assert(cliqueused[tmp] == 0);
10113 #endif
10114 
10115  maxcliqueweightsum = 0;
10116  tmp = 0;
10117 
10118  /* calculates maximal weight of cliques */
10119  for( i = 0; i < consdata->nvars; ++i )
10120  {
10121  cliquenum = consdata->cliquepartition[i];
10122  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10123 
10124  if( !cliqueused[cliquenum] )
10125  {
10126  maxcliqueweightsum += consdata->weights[i];
10127  cliqueused[cliquenum] = TRUE;
10128  tmpindices[tmp] = cliquenum;
10129  ++tmp;
10130  }
10131  }
10132  /* clear cliqueused */
10133  for( --tmp; tmp >= 0; --tmp)
10134  cliqueused[tmp] = FALSE;
10135 
10136  assert(conshdlrdata->bools4size > 0);
10137 
10138  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10139  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10140  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10141  */
10142  if( conshdlrdata->bools4size < consdata->nvars )
10143  {
10144  int oldsize = conshdlrdata->bools4size;
10145 
10146  conshdlrdata->bools4size = consdata->nvars;
10147  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10148  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10149  }
10150 
10151  itemremoved = conshdlrdata->bools4;
10152 
10153  /* check for cleared array, all entries are zero */
10154 #ifndef NDEBUG
10155  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10156  assert(itemremoved[tmp] == 0);
10157 #endif
10158 
10159  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10160  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10161  * included in subsequent cliqueweightsum calculations)
10162  */
10163  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10164  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10165  naddvars = 0;
10166  addweightsum = 0;
10167  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10168  {
10169  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10170  {
10171  SCIP_Longint cliqueweightsum;
10172  int probindex;
10173  int idx;
10174  int j;
10175 
10176  tmp = 0;
10177 
10178  probindex = liftcands[val][i];
10179  assert(0 <= probindex && probindex < nbinvars);
10180 
10181  /* ignore empty zero lists and variables that cannot be lifted anyways */
10182  if( firstidxs[val][probindex] == 0
10183  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10184  continue;
10185 
10186  /* mark the items that are implied to zero by setting the current variable to the current value */
10187  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10188  {
10189  assert(0 < idx && idx < nzeroitems);
10190  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10191  itemremoved[zeroitems[idx]] = TRUE;
10192  }
10193 
10194  /* calculate the residual cliqueweight sum */
10195  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10196  for( j = 0; j < consdata->nvars; ++j )
10197  {
10198  cliquenum = consdata->cliquepartition[j];
10199  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10200  if( !itemremoved[j] )
10201  {
10202  if( !cliqueused[cliquenum] )
10203  {
10204  cliqueweightsum += consdata->weights[j];
10205  cliqueused[cliquenum] = TRUE;
10206  tmpindices[tmp] = cliquenum;
10207  ++tmp;
10208  }
10209 
10210  if( cliqueweightsum >= consdata->capacity )
10211  break;
10212  }
10213  }
10214 
10215  /* check if the weight of the variable/value can be increased */
10216  if( cliqueweightsum < consdata->capacity )
10217  {
10218  SCIP_VAR* var;
10219  SCIP_Longint weight;
10220 
10221  /* insert the variable (with value TRUE) in the list of additional items */
10222  assert(naddvars < 2*nbinvars);
10223  var = binvars[probindex];
10224  if( val == FALSE )
10225  {
10226  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10227  }
10228  weight = consdata->capacity - cliqueweightsum;
10229  addvars[naddvars] = var;
10230  addweights[naddvars] = weight;
10231  addweightsum += weight;
10232  naddvars++;
10233 
10234  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10235  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10236  }
10237 
10238  /* clear itemremoved */
10239  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10240  {
10241  assert(0 < idx && idx < nzeroitems);
10242  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10243  itemremoved[zeroitems[idx]] = FALSE;
10244  }
10245  /* clear cliqueused */
10246  for( --tmp; tmp >= 0; --tmp)
10247  cliqueused[tmpindices[tmp]] = FALSE;
10248  }
10249  }
10250  SCIPfreeBufferArray(scip, &tmpindices);
10251 
10252  /* clear part of zeroweightsums */
10253  for( --tmp3; tmp3 >= 0; --tmp3)
10254  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10255 
10256  /* clear rest of zeroweightsums and firstidxs */
10257  for( --tmp2; tmp2 >= 0; --tmp2)
10258  {
10259  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10260  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10261  }
10262 
10263  SCIPfreeBufferArray(scip, &tmpindices2);
10264  SCIPfreeBufferArray(scip, &tmpindices3);
10265  SCIPfreeBufferArray(scip, &tmpboolindices2);
10266  SCIPfreeBufferArray(scip, &tmpboolindices3);
10267 
10268  /* add all additional item weights */
10269  for( i = 0; i < naddvars; ++i )
10270  {
10271  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10272  }
10273  *nchgcoefs += naddvars;
10274 
10275  if( naddvars > 0 )
10276  {
10277  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10278  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10279  }
10280 
10281  /* free temporary memory */
10282  SCIPfreeBufferArray(scip, &addweights);
10283  SCIPfreeBufferArray(scip, &addvars);
10284  SCIPfreeBufferArray(scip, &nextidxs);
10285  SCIPfreeBufferArray(scip, &zeroitems);
10286  SCIPfreeBufferArray(scip, &liftcands[1]);
10287  SCIPfreeBufferArray(scip, &liftcands[0]);
10288 
10289  return SCIP_OKAY;
10290 }
10291 
10292 /** tightens item weights and capacity in presolving:
10293  * given a knapsack sum(wi*xi) <= capacity
10294  * (1) let weightsum := sum(wi)
10295  * if weightsum - wi < capacity:
10296  * - not using item i would make the knapsack constraint redundant
10297  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10298  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10299  * - change coefficients:
10300  * wi' := weightsum - capacity
10301  * capacity' := capacity - (wi - wi')
10302  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10303  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10304  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10305  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10306  * can be multiple times the same weight, this can be improved
10307  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10308  * weight, to capacity - lastmininmalweightsum, e.g. :
10309  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10310  * -> minimal weightsums: 5, 5, 10, 10
10311  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10312  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10313  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10314  * (3) let W(C) be the maximal weight of clique C,
10315  * cliqueweightsum := sum(W(C))
10316  * if cliqueweightsum - W(C) < capacity:
10317  * - not using any item of C would make the knapsack constraint redundant
10318  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10319  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10320  * - change coefficients:
10321  * delta := capacity - (cliqueweightsum - W(C))
10322  * wi' := max(wi - delta, 0)
10323  * capacity' := capacity - delta
10324  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10325  * introduce infeasible solutions.
10326  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10327  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10328  * if cliqueweightsum(xi == v) < capacity:
10329  * - fixing variable xi to v would make the knapsack constraint redundant
10330  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10331  * redundancy effect:
10332  * wi' := capacity - cliqueweightsum(xi == v)
10333  * This rule can also be applied to binary variables not in the knapsack!
10334  * (5) if min{w} + wi > capacity:
10335  * - using item i would force to fix other items to zero
10336  * - wi can be increased to the capacity
10337  */
10338 static
10340  SCIP* scip, /**< SCIP data structure */
10341  SCIP_CONS* cons, /**< knapsack constraint */
10342  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10343  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10344  int* nchgsides, /**< pointer to count number of side changes */
10345  int* naddconss, /**< pointer to count number of added constraints */
10346  int* ndelconss, /**< pointer to count number of deleted constraints */
10347  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10348  )
10349 {
10350  SCIP_CONSHDLRDATA* conshdlrdata;
10351  SCIP_CONSDATA* consdata;
10352  SCIP_Longint* weights;
10353  SCIP_Longint sumcoef;
10354  SCIP_Longint capacity;
10355  SCIP_Longint newweight;
10356  SCIP_Longint maxweight;
10357  SCIP_Longint minweight;
10358  SCIP_Bool sumcoefcase = FALSE;
10359  int startpos;
10360  int backpos;
10361  int nvars;
10362  int pos;
10363  int k;
10364  int i;
10365 
10366  assert(nchgcoefs != NULL);
10367  assert(nchgsides != NULL);
10368  assert(!SCIPconsIsModifiable(cons));
10369 
10370  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10371  assert(conshdlrdata != NULL);
10372 
10373  consdata = SCIPconsGetData(cons);
10374  assert(consdata != NULL);
10375  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10376  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10377  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10378  assert(consdata->nvars > 0);
10379 
10380  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10381  if( *cutoff )
10382  return SCIP_OKAY;
10383 
10384  /* apply rule (1) */
10385  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10386  {
10387  do
10388  {
10389  assert(consdata->merged);
10390 
10391  /* sort items, s.t. the heaviest one is in the first position */
10392  sortItems(consdata);
10393 
10394  for( i = 0; i < consdata->nvars; ++i )
10395  {
10396  SCIP_Longint weight;
10397 
10398  weight = consdata->weights[i];
10399  if( consdata->weightsum - weight < consdata->capacity )
10400  {
10401  newweight = consdata->weightsum - consdata->capacity;
10402  consdataChgWeight(consdata, i, newweight);
10403  consdata->capacity -= (weight - newweight);
10404  (*nchgcoefs)++;
10405  (*nchgsides)++;
10406  assert(!consdata->sorted);
10407  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",
10408  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10409  consdata->capacity + (weight-newweight), consdata->capacity);
10410  }
10411  else
10412  break;
10413  }
10414  }
10415  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10416  }
10417 
10418  /* check for redundancy */
10419  if( consdata->weightsum <= consdata->capacity )
10420  return SCIP_OKAY;
10421 
10422  pos = 0;
10423  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10424  ++pos;
10425 
10426  sumcoef = 0;
10427  weights = consdata->weights;
10428  nvars = consdata->nvars;
10429  capacity = consdata->capacity;
10430 
10431  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10432  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10433  {
10434  /* further reductions using the next possible coefficient sum
10435  *
10436  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10437  */
10438  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10439  for( k = 0; k < 4; ++k )
10440  {
10441  newweight = capacity - sumcoef;
10442 
10443  /* determine next minimal coefficient sum */
10444  switch( k )
10445  {
10446  case 0:
10447  sumcoef = weights[nvars - 1];
10448  backpos = nvars - 1;
10449  break;
10450  case 1:
10451  sumcoef = weights[nvars - 2];
10452  backpos = nvars - 2;
10453  break;
10454  case 2:
10455  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10456  {
10457  sumcoefcase = TRUE;
10458  sumcoef = weights[nvars - 3];
10459  backpos = nvars - 3;
10460  }
10461  else
10462  {
10463  sumcoefcase = FALSE;
10464  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10465  backpos = nvars - 2;
10466  }
10467  break;
10468  default:
10469  assert(k == 3);
10470  if( sumcoefcase )
10471  {
10472  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10473  {
10474  sumcoef = weights[nvars - 4];
10475  backpos = nvars - 4;
10476  }
10477  else
10478  {
10479  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10480  backpos = nvars - 2;
10481  }
10482  }
10483  else
10484  {
10485  sumcoef = weights[nvars - 3];
10486  backpos = nvars - 3;
10487  }
10488  break;
10489  }
10490 
10491  if( backpos <= pos )
10492  break;
10493 
10494  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10495  maxweight = weights[pos];
10496  startpos = pos;
10497  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10498  {
10499  assert(newweight > weights[pos]);
10500 
10501  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10502  SCIPconsGetName(cons), maxweight, newweight);
10503 
10504  consdataChgWeight(consdata, pos, newweight);
10505 
10506  ++pos;
10507  assert(pos < nvars);
10508 
10509  maxweight = weights[pos];
10510 
10511  if( backpos <= pos )
10512  break;
10513  }
10514  (*nchgcoefs) += (pos - startpos);
10515 
10516  /* skip unchangable weights */
10517  while( pos < nvars && weights[pos] + sumcoef == capacity )
10518  ++pos;
10519 
10520  /* check special case were there is only one weight left to tighten
10521  *
10522  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10523  *
10524  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10525  *
10526  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10527  */
10528  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10529  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10530  {
10531  newweight = capacity - sumcoef;
10532  assert(newweight > weights[pos]);
10533 
10534  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10535  SCIPconsGetName(cons), maxweight, newweight);
10536 
10537  consdataChgWeight(consdata, pos, newweight);
10538 
10539  break;
10540  }
10541 
10542  if( backpos <= pos )
10543  break;
10544  }
10545  }
10546 
10547  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10548  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10549  {
10550  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10551  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10552  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10553  {
10554  SCIP_VAR** clqvars;
10555  SCIP_CONS* cliquecons;
10556  char name[SCIP_MAXSTRLEN];
10557  int* clqpart;
10558  int nclqvars;
10559  int nclq;
10560  int len;
10561  int c;
10562  int w;
10563 
10564  assert(!SCIPconsIsDeleted(cons));
10565 
10566  if( pos == consdata->nvars )
10567  {
10568  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10569 
10570  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10574  SCIPconsIsStickingAtNode(cons)) );
10575 
10576  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10577  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10578  ++(*naddconss);
10579 
10580  /* delete old constraint */
10581  SCIP_CALL( SCIPdelCons(scip, cons) );
10582  ++(*ndelconss);
10583 
10584  return SCIP_OKAY;
10585  }
10586 
10587  len = consdata->nvars - pos;
10588 
10589  /* allocate temporary memory */
10590  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10591 
10592  /* calculate clique partition */
10593  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10594  assert(nclq <= len);
10595 
10596 #ifndef NDEBUG
10597  /* clique numbers must be at least as high as the index */
10598  for( w = 0; w < nclq; ++w )
10599  assert(clqpart[w] <= w);
10600 #endif
10601 
10602  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10603 
10604  /* allocate temporary memory */
10605  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10606 
10607  /* copy corresponding variables with big coefficients */
10608  for( w = pos - 1; w >= 0; --w )
10609  clqvars[w] = consdata->vars[w];
10610 
10611  /* create for each clique a set-packing constraint */
10612  for( c = 0; c < nclq; ++c )
10613  {
10614  nclqvars = pos;
10615 
10616  for( w = c; w < len; ++w )
10617  {
10618  if( clqpart[w] == c )
10619  {
10620  assert(nclqvars < pos + len - nclq + 1);
10621  clqvars[nclqvars] = consdata->vars[w + pos];
10622  ++nclqvars;
10623  }
10624  }
10625 
10626  assert(nclqvars > 1);
10627 
10628  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10629  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10633  SCIPconsIsStickingAtNode(cons)) );
10634  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10635  SCIPdebugPrintCons(scip, cliquecons, NULL);
10636  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10637  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10638  ++(*naddconss);
10639  }
10640 
10641  /* delete old constraint */
10642  SCIP_CALL( SCIPdelCons(scip, cons) );
10643  ++(*ndelconss);
10644 
10645  SCIPfreeBufferArray(scip, &clqvars);
10646  SCIPfreeBufferArray(scip, &clqpart);
10647 
10648  return SCIP_OKAY;
10649  }
10650  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10651  {
10652  SCIP_Longint* maxcliqueweights;
10653  SCIP_Longint* newweightvals;
10654  int* newweightidxs;
10655  SCIP_Longint cliqueweightsum;
10656 
10657  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10658  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10659  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10660 
10661  /* repeat as long as changes have been applied */
10662  do
10663  {
10664  int ncliques;
10665  int cliquenum;
10666  SCIP_Bool zeroweights;
10667 
10668  assert(consdata->merged);
10669 
10670  /* sort items, s.t. the heaviest one is in the first position */
10671  sortItems(consdata);
10672 
10673  /* calculate a clique partition */
10674  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10675 
10676  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10677  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10678  break;
10679 
10680  /* calculate the maximal weight of the cliques and store the clique type */
10681  cliqueweightsum = 0;
10682  ncliques = 0;
10683 
10684  for( i = 0; i < consdata->nvars; ++i )
10685  {
10686  SCIP_Longint weight;
10687 
10688  cliquenum = consdata->cliquepartition[i];
10689  assert(0 <= cliquenum && cliquenum <= ncliques);
10690 
10691  weight = consdata->weights[i];
10692  assert(weight > 0);
10693 
10694  if( cliquenum == ncliques )
10695  {
10696  maxcliqueweights[ncliques] = weight;
10697  cliqueweightsum += weight;
10698  ++ncliques;
10699  }
10700 
10701  assert(maxcliqueweights[cliquenum] >= weight);
10702  }
10703 
10704  /* apply rule on every clique */
10705  zeroweights = FALSE;
10706  for( i = 0; i < ncliques; ++i )
10707  {
10708  SCIP_Longint delta;
10709 
10710  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10711  if( delta > 0 )
10712  {
10713  SCIP_Longint newcapacity;
10714 #ifndef NDEBUG
10715  SCIP_Longint newmincliqueweight;
10716 #endif
10717  SCIP_Longint newminweightsuminclique;
10718  SCIP_Bool forceclique;
10719  int nnewweights;
10720  int j;
10721 
10722  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",
10723  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10724  newcapacity = consdata->capacity - delta;
10725  forceclique = FALSE;
10726  nnewweights = 0;
10727 #ifndef NDEBUG
10728  newmincliqueweight = newcapacity + 1;
10729  for( j = 0; j < i; ++j )
10730  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10731 #endif
10732  for( j = i; j < consdata->nvars; ++j )
10733  {
10734  if( consdata->cliquepartition[j] == i )
10735  {
10736  newweight = consdata->weights[j] - delta;
10737  newweight = MAX(newweight, 0);
10738 
10739  /* cache the new weight */
10740  assert(nnewweights < consdata->nvars);
10741  newweightvals[nnewweights] = newweight;
10742  newweightidxs[nnewweights] = j;
10743  nnewweights++;
10744 
10745 #ifndef NDEBUG
10746  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10747  newmincliqueweight = newweight;
10748 #endif
10749  }
10750  }
10751 
10752  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10753  if( nnewweights > 1 )
10754  {
10755 #ifndef NDEBUG
10756  j = newweightidxs[nnewweights - 2];
10757  assert(0 <= j && j < consdata->nvars);
10758  assert(consdata->cliquepartition[j] == i);
10759  j = newweightidxs[nnewweights - 1];
10760  assert(0 <= j && j < consdata->nvars);
10761  assert(consdata->cliquepartition[j] == i);
10762 #endif
10763 
10764  newminweightsuminclique = newweightvals[nnewweights - 2];
10765  newminweightsuminclique += newweightvals[nnewweights - 1];
10766 
10767  /* check if these new two minimal weights both fit into the knapsack;
10768  * if this is true, we have to add a clique constraint in order to enforce the clique
10769  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10770  * reduction might be infeasible, i.e., allows additional solutions)
10771  */
10772  if( newminweightsuminclique <= newcapacity )
10773  forceclique = TRUE;
10774  }
10775 
10776  /* check if we really want to apply the change */
10777  if( conshdlrdata->disaggregation || !forceclique )
10778  {
10779  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10780  consdata->capacity, newcapacity, forceclique);
10781  consdata->capacity = newcapacity;
10782  (*nchgsides)++;
10783 
10784  for( k = 0; k < nnewweights; ++k )
10785  {
10786  j = newweightidxs[k];
10787  assert(0 <= j && j < consdata->nvars);
10788  assert(consdata->cliquepartition[j] == i);
10789 
10790  /* apply the weight change */
10791  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10792  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10793  consdataChgWeight(consdata, j, newweightvals[k]);
10794  (*nchgcoefs)++;
10795  assert(!consdata->sorted);
10796  zeroweights = zeroweights || (newweightvals[k] == 0);
10797  }
10798  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10799  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10800  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10801  * knapsack constraint
10802  */
10803  if( forceclique )
10804  {
10805  SCIP_CONS* cliquecons;
10806  char name[SCIP_MAXSTRLEN];
10807  SCIP_VAR** cliquevars;
10808 
10809  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10810  for( k = 0; k < nnewweights; ++k )
10811  cliquevars[k] = consdata->vars[newweightidxs[k]];
10812 
10813  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10814  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10818  SCIPconsIsStickingAtNode(cons)) );
10819  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10820  SCIPdebugPrintCons(scip, cliquecons, NULL);
10821  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10822  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10823  SCIPfreeBufferArray(scip, &cliquevars);
10824  (*naddconss)++;
10825  }
10826  }
10827  }
10828  }
10829  if( zeroweights )
10830  {
10831  SCIP_CALL( removeZeroWeights(scip, cons) );
10832  }
10833  }
10834  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10835 
10836  /* free temporary memory */
10837  SCIPfreeBufferArray(scip, &newweightidxs);
10838  SCIPfreeBufferArray(scip, &newweightvals);
10839  SCIPfreeBufferArray(scip, &maxcliqueweights);
10840 
10841  /* check for redundancy */
10842  if( consdata->weightsum <= consdata->capacity )
10843  return SCIP_OKAY;
10844  }
10845  }
10846 
10847  /* apply rule (3) */
10848  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10849  {
10850  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10851  }
10852 
10853  /* check for redundancy */
10854  if( consdata->weightsum <= consdata->capacity )
10855  return SCIP_OKAY;
10856 
10857  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10858  {
10859  /* apply rule (4) (all but smallest weight) */
10860  assert(consdata->merged);
10861  sortItems(consdata);
10862  minweight = consdata->weights[consdata->nvars-1];
10863  for( i = 0; i < consdata->nvars-1; ++i )
10864  {
10865  SCIP_Longint weight;
10866 
10867  weight = consdata->weights[i];
10868  assert(weight >= minweight);
10869  if( minweight + weight > consdata->capacity )
10870  {
10871  if( weight < consdata->capacity )
10872  {
10873  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10874  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10875  assert(consdata->sorted);
10876  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10877  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10878  consdata->sorted = TRUE;
10879  (*nchgcoefs)++;
10880  }
10881  }
10882  else
10883  break;
10884  }
10885 
10886  /* apply rule (5) (smallest weight) */
10887  if( consdata->nvars >= 2 )
10888  {
10889  SCIP_Longint weight;
10890 
10891  minweight = consdata->weights[consdata->nvars-2];
10892  weight = consdata->weights[consdata->nvars-1];
10893  assert(minweight >= weight);
10894  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10895  {
10896  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10897  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10898  assert(consdata->sorted);
10899  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10900  assert(minweight >= consdata->weights[consdata->nvars-1]);
10901  consdata->sorted = TRUE;
10902  (*nchgcoefs)++;
10903  }
10904  }
10905  }
10906 
10907  return SCIP_OKAY;
10908 }
10909 
10910 
10911 #ifdef SCIP_DEBUG
10912 static
10913 void printClique(
10914  SCIP_VAR** cliquevars,
10915  int ncliquevars
10916  )
10917 {
10918  int b;
10919  SCIPdebugMessage("adding new Clique: ");
10920  for( b = 0; b < ncliquevars; ++b )
10921  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10922  SCIPdebugPrintf("\n");
10923 }
10924 #endif
10925 
10926 /** adds negated cliques of the knapsack constraint to the global clique table */
10927 static
10929  SCIP*const scip, /**< SCIP data structure */
10930  SCIP_CONS*const cons, /**< knapsack constraint */
10931  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10932  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10933  )
10934 {
10935  SCIP_CONSDATA* consdata;
10936  SCIP_CONSHDLRDATA* conshdlrdata;
10937  SCIP_VAR** poscliquevars;
10938  SCIP_VAR** cliquevars;
10939  SCIP_Longint* maxweights;
10940  SCIP_Longint* gainweights;
10941  int* gaincliquepartition;
10942  SCIP_Bool* cliqueused;
10943  SCIP_Longint minactduetonegcliques;
10944  SCIP_Longint freecapacity;
10945  SCIP_Longint lastweight;
10946  SCIP_Longint beforelastweight;
10947  int nposcliquevars;
10948  int ncliquevars;
10949  int nvars;
10950  int nnegcliques;
10951  int lastcliqueused;
10952  int thisnbdchgs;
10953  int v;
10954  int w;
10955 
10956  assert(scip != NULL);
10957  assert(cons != NULL);
10958  assert(cutoff != NULL);
10959  assert(nbdchgs != NULL);
10960 
10961  *cutoff = FALSE;
10962 
10963  consdata = SCIPconsGetData(cons);
10964  assert(consdata != NULL);
10965 
10966  nvars = consdata->nvars;
10967 
10968  /* check whether the cliques have already been added */
10969  if( consdata->cliquesadded || nvars == 0 )
10970  return SCIP_OKAY;
10971 
10972  /* make sure, the items are merged */
10973  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10974  if( *cutoff )
10975  return SCIP_OKAY;
10976 
10977  /* make sure, items are sorted by non-increasing weight */
10978  sortItems(consdata);
10979 
10980  assert(consdata->merged);
10981 
10982  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10983  assert(conshdlrdata != NULL);
10984 
10985  /* calculate a clique partition */
10986  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10987  nnegcliques = consdata->nnegcliques;
10988 
10989  /* if we have no negated cliques, stop */
10990  if( nnegcliques == nvars )
10991  return SCIP_OKAY;
10992 
10993  /* get temporary memory */
10994  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10995  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10996  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
10997  BMSclearMemoryArray(gainweights, nvars);
10998  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10999  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11000  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueused, nnegcliques) );
11001  BMSclearMemoryArray(cliqueused, nnegcliques);
11002 
11003  nnegcliques = 0;
11004  minactduetonegcliques = 0;
11005 
11006  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11007  for( v = 0; v < nvars; ++v )
11008  {
11009  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11010  assert(consdata->weights[v] > 0);
11011 
11012  if( consdata->negcliquepartition[v] == nnegcliques )
11013  {
11014  nnegcliques++;
11015  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11016  }
11017  else
11018  minactduetonegcliques += consdata->weights[v];
11019  }
11020 
11021  nposcliquevars = 0;
11022 
11023  /* add cliques, using negated cliques information */
11024  if( minactduetonegcliques > 0 )
11025  {
11026  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11027  freecapacity = consdata->capacity - minactduetonegcliques;
11028 
11029  SCIPdebugPrintCons(scip, cons, NULL);
11030  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",
11031  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11032 
11033  /* calculate possible gain by switching chosen items in negated cliques */
11034  for( v = 0; v < nvars; ++v )
11035  {
11036  if( !cliqueused[consdata->negcliquepartition[v]] )
11037  {
11038  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11039  for( w = v + 1; w < nvars; ++w )
11040  {
11041  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11042  * weight[w] (which are both in a negated clique) */
11043  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11044  && consdata->weights[v] > consdata->weights[w] )
11045  {
11046  poscliquevars[nposcliquevars] = consdata->vars[w];
11047  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11048  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11049  ++nposcliquevars;
11050  }
11051  }
11052  }
11053  }
11054 
11055  /* try to create negated cliques */
11056  if( nposcliquevars > 0 )
11057  {
11058  /* sort possible gain per substitution of the clique members */
11059  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11060 
11061  for( v = 0; v < nposcliquevars; ++v )
11062  {
11063  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11064  ncliquevars = 1;
11065  lastweight = gainweights[v];
11066  beforelastweight = -1;
11067  lastcliqueused = gaincliquepartition[v];
11068  /* clear cliqueused to get an unused array */
11069  BMSclearMemoryArray(cliqueused, nnegcliques);
11070  cliqueused[gaincliquepartition[v]] = TRUE;
11071 
11072  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11073  * in the same negated clique and by taking two of them would exceed the free capacity */
11074  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11075  {
11076  beforelastweight = lastweight;
11077  lastweight = gainweights[w];
11078  lastcliqueused = gaincliquepartition[w];
11079  cliqueused[gaincliquepartition[w]] = TRUE;
11080  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11081  ++ncliquevars;
11082  }
11083 
11084  if( ncliquevars > 1 )
11085  {
11086  SCIPdebug( printClique(cliquevars, ncliquevars) );
11087  assert(beforelastweight > 0);
11088  /* add the clique to the clique table */
11089  /* this really happens, e.g., on enigma.mps from the short test set */
11090  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11091  if( *cutoff )
11092  goto TERMINATE;
11093  *nbdchgs += thisnbdchgs;
11094 
11095  /* reset last used clique to get slightly different cliques */
11096  cliqueused[lastcliqueused] = FALSE;
11097 
11098  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11099  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11100  {
11101  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11102  SCIPdebug( printClique(cliquevars, ncliquevars) );
11103  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11104  if( *cutoff )
11105  goto TERMINATE;
11106  *nbdchgs += thisnbdchgs;
11107  }
11108  }
11109  }
11110  }
11111  }
11112 
11113  TERMINATE:
11114  /* free temporary memory */
11115  SCIPfreeBufferArray(scip, &cliqueused);
11116  SCIPfreeBufferArray(scip, &gaincliquepartition);
11117  SCIPfreeBufferArray(scip, &maxweights);
11118  SCIPfreeBufferArray(scip, &gainweights);
11119  SCIPfreeBufferArray(scip, &cliquevars);
11120  SCIPfreeBufferArray(scip, &poscliquevars);
11121 
11122  return SCIP_OKAY;
11123 }
11124 
11125 /** greedy clique detection by considering weights and capacity
11126  *
11127  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11128  * 1) neighboring items which exceed the capacity together => one clique
11129  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11130  */
11131 static
11133  SCIP*const scip, /**< SCIP data structure */
11134  SCIP_VAR** items, /**< array of variable items */
11135  SCIP_Longint* weights, /**< weights of the items */
11136  int nitems, /**< the number of items */
11137  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11138  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11139  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11140  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11141  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11142  )
11143 {
11144  SCIP_Longint lastweight;
11145  int ncliquevars;
11146  int i;
11147  int thisnbdchgs;
11148 
11149  if( nitems <= 1 )
11150  return SCIP_OKAY;
11151 
11152  /* sort possible gain per substitution of the clique members */
11153  if( ! sorteditems )
11154  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11155 
11156  ncliquevars = 1;
11157  lastweight = weights[0];
11158 
11159  /* taking these two weights together violates the knapsack => include into clique */
11160  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11161  {
11162  lastweight = weights[i];
11163  ++ncliquevars;
11164  }
11165 
11166  if( ncliquevars > 1 )
11167  {
11168  SCIP_Longint compareweight;
11169  SCIP_VAR** cliquevars;
11170  int compareweightidx;
11171  int minclqsize;
11172  int nnzadded;
11173 
11174  /* add the clique to the clique table */
11175  SCIPdebug( printClique(items, ncliquevars) );
11176  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11177 
11178  if( *cutoff )
11179  return SCIP_OKAY;
11180 
11181  *nbdchgs += thisnbdchgs;
11182  nnzadded = ncliquevars;
11183 
11184  /* 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)*/
11185  if( ncliquevars == nitems )
11186  return SCIP_OKAY;
11187 
11188  /* copy items in order into buffer array and deduce more cliques */
11189  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11190 
11191  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11192  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11193  compareweightidx = ncliquevars - 2;
11194  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11195 
11196  /* determine minimum clique size for the following loop */
11197  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11198  minclqsize = MAX(minclqsize, 2);
11199 
11200  /* loop over the remaining variables and the larger items of the first clique until we
11201  * find another clique or reach the size limit */
11202  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11203  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11204  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11205  )
11206  {
11207  compareweight = weights[compareweightidx];
11208  assert(compareweight > 0);
11209 
11210  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11211  if( compareweight + weights[i] > capacity )
11212  {
11213  assert(compareweightidx == ncliquevars -2);
11214  cliquevars[ncliquevars - 1] = items[i];
11215  SCIPdebug( printClique(cliquevars, ncliquevars) );
11216  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11217 
11218  nnzadded += ncliquevars;
11219 
11220  /* stop when there is a cutoff */
11221  if( ! (*cutoff) )
11222  *nbdchgs += thisnbdchgs;
11223 
11224  /* go to next smaller item */
11225  ++i;
11226  }
11227  else
11228  {
11229  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11230  compareweightidx--;
11231  ncliquevars --;
11232  }
11233  }
11234 
11235  SCIPfreeBufferArray(scip, &cliquevars);
11236  }
11237 
11238  return SCIP_OKAY;
11239 }
11240 
11241 /** adds cliques of the knapsack constraint to the global clique table */
11242 static
11244  SCIP*const scip, /**< SCIP data structure */
11245  SCIP_CONS*const cons, /**< knapsack constraint */
11246  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11247  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11248  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11249  )
11250 {
11251  SCIP_CONSDATA* consdata;
11252  SCIP_CONSHDLRDATA* conshdlrdata;
11253  int i;
11254  SCIP_Longint minactduetonegcliques;
11255  SCIP_Longint freecapacity;
11256  int nnegcliques;
11257  int cliquenum;
11258  SCIP_VAR** poscliquevars;
11259  SCIP_Longint* gainweights;
11260  int nposcliquevars;
11261  SCIP_Longint* secondmaxweights;
11262  int nvars;
11263 
11264  assert(scip != NULL);
11265  assert(cons != NULL);
11266  assert(cutoff != NULL);
11267  assert(nbdchgs != NULL);
11268 
11269  *cutoff = FALSE;
11270 
11271  consdata = SCIPconsGetData(cons);
11272  assert(consdata != NULL);
11273 
11274  nvars = consdata->nvars;
11275 
11276  /* check whether the cliques have already been added */
11277  if( consdata->cliquesadded || nvars == 0 )
11278  return SCIP_OKAY;
11279 
11280  /* make sure, the items are merged */
11281  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11282  if( *cutoff )
11283  return SCIP_OKAY;
11284 
11285  /* make sure, the items are sorted by non-increasing weight */
11286  sortItems(consdata);
11287 
11288  assert(consdata->merged);
11289 
11290  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11291  assert(conshdlrdata != NULL);
11292 
11293  /* calculate a clique partition */
11294  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11295  nnegcliques = consdata->nnegcliques;
11296  assert(nnegcliques <= nvars);
11297 
11298  /* get temporary memory */
11299  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11300  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11301  BMSclearMemoryArray(gainweights, nvars);
11302  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11303  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11304 
11305  minactduetonegcliques = 0;
11306 
11307  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11308  if( nnegcliques < nvars )
11309  {
11310  nnegcliques = 0;
11311 
11312  for( i = 0; i < nvars; ++i )
11313  {
11314  SCIP_Longint weight;
11315 
11316  cliquenum = consdata->negcliquepartition[i];
11317  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11318 
11319  weight = consdata->weights[i];
11320  assert(weight > 0);
11321 
11322  if( cliquenum == nnegcliques )
11323  nnegcliques++;
11324  else
11325  {
11326  minactduetonegcliques += weight;
11327  if( secondmaxweights[cliquenum] == 0 )
11328  secondmaxweights[cliquenum] = weight;
11329  }
11330  }
11331  }
11332 
11333  /* add cliques, using negated cliques information */
11334  if( minactduetonegcliques > 0 )
11335  {
11336  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11337  freecapacity = consdata->capacity - minactduetonegcliques;
11338 
11339  SCIPdebugPrintCons(scip, cons, NULL);
11340  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",
11341  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11342 
11343  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11344  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11345 
11346  if( *cutoff )
11347  goto TERMINATE;
11348 
11349  nposcliquevars = 0;
11350 
11351  for( i = nvars - 1; i >= 0; --i )
11352  {
11353  /* if we would take the biggest weight instead of the second biggest */
11354  cliquenum = consdata->negcliquepartition[i];
11355  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11356  {
11357  poscliquevars[nposcliquevars] = consdata->vars[i];
11358  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11359  ++nposcliquevars;
11360  }
11361  }
11362 
11363  /* use the gain weights and free capacity to derive greedily cliques */
11364  if( nposcliquevars > 1 )
11365  {
11366  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11367 
11368  if( *cutoff )
11369  goto TERMINATE;
11370  }
11371  }
11372 
11373  /* build cliques by using the items with the maximal weights */
11374  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11375 
11376  TERMINATE:
11377  /* free temporary memory and mark the constraint */
11378  SCIPfreeBufferArray(scip, &secondmaxweights);
11379  SCIPfreeBufferArray(scip, &gainweights);
11380  SCIPfreeBufferArray(scip, &poscliquevars);
11381  consdata->cliquesadded = TRUE;
11382 
11383  return SCIP_OKAY;
11384 }
11385 
11386 
11387 /** gets the key of the given element */
11388 static
11389 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11390 { /*lint --e{715}*/
11391  /* the key is the element itself */
11392  return elem;
11393 }
11394 
11395 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11396  * same coefficients
11397  */
11398 static
11399 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11400 {
11401 #ifndef NDEBUG
11402  SCIP* scip;
11403 #endif
11404  SCIP_CONSDATA* consdata1;
11405  SCIP_CONSDATA* consdata2;
11406  int i;
11408  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11409  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11410  assert(consdata1->sorted);
11411  assert(consdata2->sorted);
11412 #ifndef NDEBUG
11413  scip = (SCIP*)userptr;
11414  assert(scip != NULL);
11415 #endif
11416 
11417  /* checks trivial case */
11418  if( consdata1->nvars != consdata2->nvars )
11419  return FALSE;
11420 
11421  for( i = consdata1->nvars - 1; i >= 0; --i )
11422  {
11423  /* tests if variables are equal */
11424  if( consdata1->vars[i] != consdata2->vars[i] )
11425  {
11426  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11427  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11428  return FALSE;
11429  }
11430  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11431 
11432  /* tests if weights are equal too */
11433  if( consdata1->weights[i] != consdata2->weights[i] )
11434  return FALSE;
11435  }
11436 
11437  return TRUE;
11438 }
11439 
11440 /** returns the hash value of the key */
11441 static
11442 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11443 {
11444 #ifndef NDEBUG
11445  SCIP* scip;
11446 #endif
11447  SCIP_CONSDATA* consdata;
11448  int minidx;
11449  int mididx;
11450  int maxidx;
11451 
11452  consdata = SCIPconsGetData((SCIP_CONS*)key);
11453  assert(consdata != NULL);
11454  assert(consdata->nvars > 0);
11455 
11456 #ifndef NDEBUG
11457  scip = (SCIP*)userptr;
11458  assert(scip != NULL);
11459 #endif
11460 
11461  /* sorts the constraints */
11462  sortItems(consdata);
11463 
11464  minidx = SCIPvarGetIndex(consdata->vars[0]);
11465  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11466  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11467  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11468 
11469  /* hash value depends on vectors of variable indices */
11470  return SCIPhashTwo(SCIPcombineFourInt(consdata->nvars, minidx, mididx, maxidx),
11471  consdata->weights[0]);
11472 }
11473 
11474 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11475  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11476  */
11477 static
11479  SCIP* scip, /**< SCIP data structure */
11480  BMS_BLKMEM* blkmem, /**< block memory */
11481  SCIP_CONS** conss, /**< constraint set */
11482  int nconss, /**< number of constraints in constraint set */
11483  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11484  int* ndelconss /**< pointer to count number of deleted constraints */
11485  )
11487  SCIP_HASHTABLE* hashtable;
11488  int hashtablesize;
11489  int c;
11490 
11491  assert(scip != NULL);
11492  assert(blkmem != NULL);
11493  assert(conss != NULL);
11494  assert(ndelconss != NULL);
11495 
11496  /* create a hash table for the constraint set */
11497  hashtablesize = nconss;
11498  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11499  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11500  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11501 
11502  /* check all constraints in the given set for redundancy */
11503  for( c = nconss - 1; c >= 0; --c )
11504  {
11505  SCIP_CONS* cons0;
11506  SCIP_CONS* cons1;
11507  SCIP_CONSDATA* consdata0;
11508 
11509  cons0 = conss[c];
11510 
11511  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11512  continue;
11513 
11514  consdata0 = SCIPconsGetData(cons0);
11515  assert(consdata0 != NULL);
11516  if( consdata0->nvars == 0 )
11517  {
11518  if( consdata0->capacity < 0 )
11519  {
11520  *cutoff = TRUE;
11521  goto TERMINATE;
11522  }
11523  else
11524  {
11525  SCIP_CALL( SCIPdelCons(scip, cons0) );
11526  ++(*ndelconss);
11527  continue;
11528  }
11529  }
11530 
11531  /* get constraint from current hash table with same variables and same weights as cons0 */
11532  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11533 
11534  if( cons1 != NULL )
11535  {
11536  SCIP_CONS* consstay;
11537  SCIP_CONS* consdel;
11538  SCIP_CONSDATA* consdata1;
11539 
11540  assert(SCIPconsIsActive(cons1));
11541  assert(!SCIPconsIsModifiable(cons1));
11542 
11543  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11544  * delete old constraints afterwards
11545  */
11546  consdata1 = SCIPconsGetData(cons1);
11547 
11548  assert(consdata1 != NULL);
11549  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11550 
11551  assert(consdata0->sorted && consdata1->sorted);
11552  assert(consdata0->vars[0] == consdata1->vars[0]);
11553  assert(consdata0->weights[0] == consdata1->weights[0]);
11554 
11555  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11556  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11557 
11558  /* check which constraint has to stay; */
11559  if( consdata0->capacity < consdata1->capacity )
11560  {
11561  consstay = cons0;
11562  consdel = cons1;
11563 
11564  /* exchange consdel with consstay in hashtable */
11565  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11566  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11567  }
11568  else
11569  {
11570  consstay = cons1;
11571  consdel = cons0;
11572  }
11573 
11574  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11575  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11576 
11577  /* delete consdel */
11578  SCIP_CALL( SCIPdelCons(scip, consdel) );
11579  ++(*ndelconss);
11580 
11581  assert(SCIPconsIsActive(consstay));
11582  }
11583  else
11584  {
11585  /* no such constraint in current hash table: insert cons0 into hash table */
11586  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11587  }
11588  }
11589 
11590  TERMINATE:
11591  /* free hash table */
11592  SCIPhashtableFree(&hashtable);
11593 
11594  return SCIP_OKAY;
11595 }
11596 
11597 
11598 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11599  * and removes or changes constraint accordingly
11600  */
11601 static
11603  SCIP* scip, /**< SCIP data structure */
11604  SCIP_CONS** conss, /**< constraint set */
11605  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11606  int chkind, /**< index of constraint to check against all prior indices upto startind */
11607  int* ndelconss /**< pointer to count number of deleted constraints */
11608  )
11609 {
11610  SCIP_CONS* cons0;
11611  SCIP_CONSDATA* consdata0;
11612  int c;
11613 
11614  assert(scip != NULL);
11615  assert(conss != NULL);
11616  assert(firstchange <= chkind);
11617  assert(ndelconss != NULL);
11618 
11619  /* get the constraint to be checked against all prior constraints */
11620  cons0 = conss[chkind];
11621  assert(cons0 != NULL);
11622  assert(SCIPconsIsActive(cons0));
11623  assert(!SCIPconsIsModifiable(cons0));
11624 
11625  consdata0 = SCIPconsGetData(cons0);
11626  assert(consdata0 != NULL);
11627  assert(consdata0->nvars >= 1);
11628  assert(consdata0->merged);
11629 
11630  /* sort the constraint */
11631  sortItems(consdata0);
11632 
11633  /* check constraint against all prior constraints */
11634  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11635  {
11636  SCIP_CONS* cons1;
11637  SCIP_CONSDATA* consdata1;
11638  SCIP_Bool iscons0incons1contained;
11639  SCIP_Bool iscons1incons0contained;
11640  SCIP_Real quotient;
11641  int v;
11642  int v0;
11643  int v1;
11644 
11645  cons1 = conss[c];
11646  assert(cons1 != NULL);
11647  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11648  continue;
11649 
11650  consdata1 = SCIPconsGetData(cons1);
11651  assert(consdata1 != NULL);
11652 
11653  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11654  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11655  continue;
11656 
11657  assert(consdata1->nvars >= 1);
11658  assert(consdata1->merged);
11659 
11660  /* sort the constraint */
11661  sortItems(consdata1);
11662 
11663  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11664 
11665  if( consdata0->nvars > consdata1->nvars )
11666  {
11667  iscons0incons1contained = FALSE;
11668  iscons1incons0contained = TRUE;
11669  v = consdata1->nvars - 1;
11670  }
11671  else if( consdata0->nvars < consdata1->nvars )
11672  {
11673  iscons0incons1contained = TRUE;
11674  iscons1incons0contained = FALSE;
11675  v = consdata0->nvars - 1;
11676  }
11677  else
11678  {
11679  iscons0incons1contained = TRUE;
11680  iscons1incons0contained = TRUE;
11681  v = consdata0->nvars - 1;
11682  }
11683 
11684  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11685 
11686  /* check consdata0 against consdata1:
11687  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11688  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11689  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11690  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11691  */
11692  v0 = consdata0->nvars - 1;
11693  v1 = consdata1->nvars - 1;
11694 
11695  while( v >= 0 )
11696  {
11697  assert(iscons0incons1contained || iscons1incons0contained);
11698 
11699  /* now there are more variables in cons1 left */
11700  if( v1 > v0 )
11701  {
11702  iscons1incons0contained = FALSE;
11703  if( !iscons0incons1contained )
11704  break;
11705  }
11706  /* now there are more variables in cons0 left */
11707  else if( v1 < v0 )
11708  {
11709  iscons0incons1contained = FALSE;
11710  if( !iscons1incons0contained )
11711  break;
11712  }
11713 
11714  assert(v == v0 || v == v1);
11715  assert(v0 >= 0);
11716  assert(v1 >= 0);
11717 
11718  /* both variables are the same */
11719  if( consdata0->vars[v0] == consdata1->vars[v1] )
11720  {
11721  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11722  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11723  {
11724  iscons1incons0contained = FALSE;
11725  if( !iscons0incons1contained )
11726  break;
11727  }
11728  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11729  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11730  {
11731  iscons0incons1contained = FALSE;
11732  if( !iscons1incons0contained )
11733  break;
11734  }
11735  --v0;
11736  --v1;
11737  --v;
11738  }
11739  else
11740  {
11741  /* both constraints have a variables which is not part of the other constraint, so stop */
11742  if( iscons0incons1contained && iscons1incons0contained )
11743  {
11744  iscons0incons1contained = FALSE;
11745  iscons1incons0contained = FALSE;
11746  break;
11747  }
11748  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11749  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11750  /* continue to the next variable */
11751  if( iscons0incons1contained )
11752  --v1;
11753  else
11754  --v0;
11755  }
11756  }
11757  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11758  * other
11759  */
11760  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11761 
11762  if( iscons1incons0contained )
11763  {
11764  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11765  SCIPdebugPrintCons(scip, cons1, NULL);
11766 
11767  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11768  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11769 
11770  SCIP_CALL( SCIPdelCons(scip, cons1) );
11771  ++(*ndelconss);
11772  }
11773  else if( iscons0incons1contained )
11774  {
11775  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11776  SCIPdebugPrintCons(scip, cons0, NULL);
11777 
11778  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11779  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11780 
11781  SCIP_CALL( SCIPdelCons(scip, cons0) );
11782  ++(*ndelconss);
11783  break;
11784  }
11785  }
11786 
11787  return SCIP_OKAY;
11788 }
11789 
11790 /** helper function to enforce constraints */
11791 static
11793  SCIP* scip, /**< SCIP data structure */
11794  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11795  SCIP_CONS** conss, /**< constraints to process */
11796  int nconss, /**< number of constraints */
11797  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11798  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11799  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11800  )
11801 {
11802  SCIP_CONSHDLRDATA* conshdlrdata;
11803  SCIP_Bool violated;
11804  SCIP_Bool cutoff = FALSE;
11805  int maxncuts;
11806  int ncuts = 0;
11807  int i;
11808 
11809  *result = SCIP_FEASIBLE;
11810 
11811  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11812  sol == NULL ? "LP" : "relaxation");
11813 
11814  /* get maximal number of cuts per round */
11815  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11816  assert(conshdlrdata != NULL);
11817  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11818 
11819  /* search for violated useful knapsack constraints */
11820  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11821  {
11822  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11823  if( violated )
11824  {
11825  /* add knapsack constraint as LP row to the relaxation */
11826  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11827  ncuts++;
11828  }
11829  }
11830 
11831  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11832  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11833  {
11834  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11835  if( violated )
11836  {
11837  /* add knapsack constraint as LP row to the relaxation */
11838  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11839  ncuts++;
11840  }
11841  }
11842 
11843  /* adjust the result code */
11844  if ( cutoff )
11845  *result = SCIP_CUTOFF;
11846  else if ( ncuts > 0 )
11847  *result = SCIP_SEPARATED;
11848 
11849  return SCIP_OKAY;
11850 }
11851 
11852 /*
11853  * Linear constraint upgrading
11854  */
11855 
11856 /** creates and captures a knapsack constraint out of a linear inequality */
11857 static
11859  SCIP* scip, /**< SCIP data structure */
11860  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11861  const char* name, /**< name of constraint */
11862  int nvars, /**< number of variables in the constraint */
11863  SCIP_VAR** vars, /**< array with variables of constraint entries */
11864  SCIP_Real* vals, /**< array with inequality coefficients */
11865  SCIP_Real lhs, /**< left hand side of inequality */
11866  SCIP_Real rhs, /**< right hand side of inequality */
11867  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11868  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11869  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11870  * Usually set to TRUE. */
11871  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11872  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11873  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11874  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11875  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11876  * Usually set to TRUE. */
11877  SCIP_Bool local, /**< is constraint only valid locally?
11878  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11879  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11880  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11881  * adds coefficients to this constraint. */
11882  SCIP_Bool dynamic, /**< is constraint subject to aging?
11883  * Usually set to FALSE. Set to TRUE for own cuts which
11884  * are separated as constraints. */
11885  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11886  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11887  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11888  * if it may be moved to a more global node?
11889  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11890  )
11891 {
11892  SCIP_VAR** transvars;
11893  SCIP_Longint* weights;
11894  SCIP_Longint capacity;
11895  SCIP_Longint weight;
11896  int mult;
11897  int v;
11898 
11899  assert(nvars == 0 || vars != NULL);
11900  assert(nvars == 0 || vals != NULL);
11901  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11902 
11903  /* get temporary memory */
11904  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11905  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11906 
11907  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11908  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11909  */
11910  if( SCIPisInfinity(scip, rhs) )
11911  {
11912  mult = -1;
11913  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11914  }
11915  else
11916  {
11917  mult = +1;
11918  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11919  }
11920 
11921  /* negate positive or negative variables */
11922  for( v = 0; v < nvars; ++v )
11923  {
11924  assert(SCIPisFeasIntegral(scip, vals[v]));
11925  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11926  if( weight > 0 )
11927  {
11928  transvars[v] = vars[v];
11929  weights[v] = weight;
11930  }
11931  else
11932  {
11933  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11934  weights[v] = -weight;
11935  capacity -= weight;
11936  }
11937  assert(transvars[v] != NULL);
11938  }
11939 
11940  /* create the constraint */
11941  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11942  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11943 
11944  /* free temporary memory */
11945  SCIPfreeBufferArray(scip, &weights);
11946  SCIPfreeBufferArray(scip, &transvars);
11947 
11948  return SCIP_OKAY;
11949 }
11950 
11951 /** tries to upgrade a linear constraint into a knapsack constraint */
11952 static
11953 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11954 { /*lint --e{715}*/
11955  SCIP_Bool upgrade;
11956 
11957  assert(upgdcons != NULL);
11958 
11959  /* check, if linear constraint can be upgraded to a knapsack constraint
11960  * - all variables must be binary
11961  * - all coefficients must be integral
11962  * - exactly one of the sides must be infinite
11963  */
11964  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11965  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11966  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11967 
11968  if( upgrade )
11969  {
11970  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11971 
11972  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11973  assert(!SCIPconsIsModifiable(cons));
11974  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11979  }
11980 
11981  return SCIP_OKAY;
11982 }
11983 
11984 
11985 /*
11986  * Callback methods of constraint handler
11987  */
11988 
11989 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11990 /**! [SnippetConsCopyKnapsack] */
11991 static
11992 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11993 { /*lint --e{715}*/
11994  assert(scip != NULL);
11995  assert(conshdlr != NULL);
11996  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11997 
11998  /* call inclusion method of constraint handler */
12001  *valid = TRUE;
12002 
12003  return SCIP_OKAY;
12004 }
12005 /**! [SnippetConsCopyKnapsack] */
12006 
12007 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12008 /**! [SnippetConsFreeKnapsack] */
12009 static
12010 SCIP_DECL_CONSFREE(consFreeKnapsack)
12011 { /*lint --e{715}*/
12012  SCIP_CONSHDLRDATA* conshdlrdata;
12013 
12014  /* free constraint handler data */
12015  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12016  assert(conshdlrdata != NULL);
12017 
12018  SCIPfreeBlockMemory(scip, &conshdlrdata);
12019 
12020  SCIPconshdlrSetData(conshdlr, NULL);
12021 
12022  return SCIP_OKAY;
12023 }
12024 /**! [SnippetConsFreeKnapsack] */
12025 
12026 
12027 /** initialization method of constraint handler (called after problem was transformed) */
12028 static
12029 SCIP_DECL_CONSINIT(consInitKnapsack)
12030 { /*lint --e{715}*/
12031  SCIP_CONSHDLRDATA* conshdlrdata;
12032  int nvars;
12033 
12034  assert( scip != NULL );
12035  assert( conshdlr != NULL );
12036 
12037  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12038  assert(conshdlrdata != NULL);
12039 
12040  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12041  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12042 
12043  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12044  conshdlrdata->reals1size = nvars;
12045 
12046  return SCIP_OKAY;
12047 }
12048 
12049 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12050 static
12051 SCIP_DECL_CONSEXIT(consExitKnapsack)
12052 { /*lint --e{715}*/
12053  SCIP_CONSHDLRDATA* conshdlrdata;
12054 
12055  assert( scip != NULL );
12056  assert( conshdlr != NULL );
12057 
12058  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12059  assert(conshdlrdata != NULL);
12060 
12061  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12062  conshdlrdata->reals1size = 0;
12063 
12064  return SCIP_OKAY;
12065 }
12066 
12067 
12068 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12069 static
12070 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12071 { /*lint --e{715}*/
12072  SCIP_CONSHDLRDATA* conshdlrdata;
12073  int nvars;
12074 
12075  assert(scip != NULL);
12076  assert(conshdlr != NULL);
12077  assert(nconss == 0 || conss != NULL);
12079  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12080  assert(conshdlrdata != NULL);
12081 
12082  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12083  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12084 
12085  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12086  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12087  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12088  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12089  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12090  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12091  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12092  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12093 
12094  conshdlrdata->ints1size = nvars;
12095  conshdlrdata->ints2size = nvars;
12096  conshdlrdata->longints1size = nvars;
12097  conshdlrdata->longints2size = nvars;
12098  conshdlrdata->bools1size = nvars;
12099  conshdlrdata->bools2size = nvars;
12100  conshdlrdata->bools3size = nvars;
12101  conshdlrdata->bools4size = nvars;
12102 
12103 #ifdef WITH_CARDINALITY_UPGRADE
12104  conshdlrdata->upgradedcard = FALSE;
12105 #endif
12106 
12107  return SCIP_OKAY;
12108 }
12109 
12110 
12111 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12112 static
12113 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12114 { /*lint --e{715}*/
12115  SCIP_CONSHDLRDATA* conshdlrdata;
12116  int c;
12117 
12118  assert(scip != NULL);
12119  assert(conshdlr != NULL);
12120 
12121  for( c = 0; c < nconss; ++c )
12122  {
12123  if( !SCIPconsIsDeleted(conss[c]) )
12124  {
12125  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12126  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12127  }
12128  }
12129 
12130  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12131  assert(conshdlrdata != NULL);
12132 
12133  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12134  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12135  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12136  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12137  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12138  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12139  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12140  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12141 
12142  conshdlrdata->ints1size = 0;
12143  conshdlrdata->ints2size = 0;
12144  conshdlrdata->longints1size = 0;
12145  conshdlrdata->longints2size = 0;
12146  conshdlrdata->bools1size = 0;
12147  conshdlrdata->bools2size = 0;
12148  conshdlrdata->bools3size = 0;
12149  conshdlrdata->bools4size = 0;
12150 
12151  return SCIP_OKAY;
12152 }
12153 
12154 
12155 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12156 static
12157 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12158 { /*lint --e{715}*/
12159  SCIP_CONSDATA* consdata;
12160  int c;
12161 
12162  assert( scip != NULL );
12163 
12164  /* release the rows of all constraints */
12165  for( c = 0; c < nconss; ++c )
12166  {
12167  consdata = SCIPconsGetData(conss[c]);
12168  assert(consdata != NULL);
12169 
12170  if( consdata->row != NULL )
12171  {
12172  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12173  }
12174  }
12175 
12176  return SCIP_OKAY;
12177 }
12178 
12179 /** frees specific constraint data */
12180 static
12181 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12182 { /*lint --e{715}*/
12183  SCIP_CONSHDLRDATA* conshdlrdata;
12184 
12185  assert(conshdlr != NULL);
12186  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12187 
12188  /* get event handler */
12189  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12190  assert(conshdlrdata != NULL);
12191  assert(conshdlrdata->eventhdlr != NULL);
12192 
12193  /* free knapsack constraint */
12194  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12195 
12196  return SCIP_OKAY;
12197 }
12198 
12199 /** transforms constraint data into data belonging to the transformed problem */
12200 /**! [SnippetConsTransKnapsack]*/
12201 static
12202 SCIP_DECL_CONSTRANS(consTransKnapsack)
12203 { /*lint --e{715}*/
12204  SCIP_CONSHDLRDATA* conshdlrdata;
12205  SCIP_CONSDATA* sourcedata;
12206  SCIP_CONSDATA* targetdata;
12207 
12208  assert(conshdlr != NULL);
12209  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12211  assert(sourcecons != NULL);
12212  assert(targetcons != NULL);
12213 
12214  sourcedata = SCIPconsGetData(sourcecons);
12215  assert(sourcedata != NULL);
12216  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12217 
12218  /* get event handler */
12219  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12220  assert(conshdlrdata != NULL);
12221  assert(conshdlrdata->eventhdlr != NULL);
12222 
12223  /* create target constraint data */
12224  SCIP_CALL( consdataCreate(scip, &targetdata,
12225  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12226 
12227  /* create target constraint */
12228  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12229  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12230  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12231  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12232  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12233 
12234  /* catch events for variables */
12235  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12236 
12237  return SCIP_OKAY;
12238 }
12239 /**! [SnippetConsTransKnapsack]*/
12240 
12241 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12242 static
12243 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12244 { /*lint --e{715}*/
12245  int i;
12246 
12247  *infeasible = FALSE;
12248 
12249  for( i = 0; i < nconss && !(*infeasible); i++ )
12250  {
12251  assert(SCIPconsIsInitial(conss[i]));
12252  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12253  }
12254 
12255  return SCIP_OKAY;
12256 }
12257 
12258 /** separation method of constraint handler for LP solutions */
12259 static
12260 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12261 { /*lint --e{715}*/
12262  SCIP_CONSHDLRDATA* conshdlrdata;
12263  SCIP_Bool sepacardinality;
12264  SCIP_Bool cutoff;
12265 
12266  SCIP_Real loclowerbound;
12267  SCIP_Real glblowerbound;
12268  SCIP_Real cutoffbound;
12269  SCIP_Real maxbound;
12270 
12271  int depth;
12272  int nrounds;
12273  int sepafreq;
12274  int sepacardfreq;
12275  int ncuts;
12276  int maxsepacuts;
12277  int i;
12278 
12279  *result = SCIP_DIDNOTRUN;
12280 
12281  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12282  assert(conshdlrdata != NULL);
12283 
12284  depth = SCIPgetDepth(scip);
12285  nrounds = SCIPgetNSepaRounds(scip);
12286 
12287  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12288  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12289 
12290  /* only call the separator a given number of times at each node */
12291  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12292  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12293  return SCIP_OKAY;
12294 
12295  /* check, if we should additionally separate knapsack cuts */
12296  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12297  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12298  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12299  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12300 
12301  /* check dual bound to see if we want to produce knapsack cuts at this node */
12302  loclowerbound = SCIPgetLocalLowerbound(scip);
12303  glblowerbound = SCIPgetLowerbound(scip);
12304  cutoffbound = SCIPgetCutoffbound(scip);
12305  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12306  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12307  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12308 
12309  /* get the maximal number of cuts allowed in a separation round */
12310  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12311 
12312  *result = SCIP_DIDNOTFIND;
12313  ncuts = 0;
12314  cutoff = FALSE;
12315 
12316  /* separate useful constraints */
12317  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12318  {
12319  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12320  }
12321 
12322  /* adjust return value */
12323  if ( cutoff )
12324  *result = SCIP_CUTOFF;
12325  else if ( ncuts > 0 )
12326  *result = SCIP_SEPARATED;
12327 
12328  return SCIP_OKAY;
12329 }
12330 
12331 
12332 /** separation method of constraint handler for arbitrary primal solutions */
12333 static
12334 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12335 { /*lint --e{715}*/
12336  SCIP_CONSHDLRDATA* conshdlrdata;
12337  SCIP_Bool sepacardinality;
12338  SCIP_Bool cutoff;
12339 
12340  int depth;
12341  int nrounds;
12342  int sepafreq;
12343  int sepacardfreq;
12344  int ncuts;
12345  int maxsepacuts;
12346  int i;
12347 
12348  *result = SCIP_DIDNOTRUN;
12349 
12350  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12351  assert(conshdlrdata != NULL);
12352 
12353  depth = SCIPgetDepth(scip);
12354  nrounds = SCIPgetNSepaRounds(scip);
12355 
12356  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12357  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12358 
12359  /* only call the separator a given number of times at each node */
12360  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12361  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12362  return SCIP_OKAY;
12363 
12364  /* check, if we should additionally separate knapsack cuts */
12365  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12366  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12367  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12368  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12369 
12370  /* get the maximal number of cuts allowed in a separation round */
12371  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12372 
12373  *result = SCIP_DIDNOTFIND;
12374  ncuts = 0;
12375  cutoff = FALSE;
12376 
12377  /* separate useful constraints */
12378  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12379  {
12380  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12381  }
12382 
12383  /* adjust return value */
12384  if ( cutoff )
12385  *result = SCIP_CUTOFF;
12386  else if( ncuts > 0 )
12387  *result = SCIP_SEPARATED;
12388 
12389  return SCIP_OKAY;
12390 }
12391 
12392 /** constraint enforcing method of constraint handler for LP solutions */
12393 static
12394 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12395 { /*lint --e{715}*/
12396  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12397 
12398  return SCIP_OKAY;
12399 }
12400 
12401 /** constraint enforcing method of constraint handler for relaxation solutions */
12402 static
12403 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12404 { /*lint --e{715}*/
12405  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12406 
12407  return SCIP_OKAY;
12408 }
12409 
12410 /** constraint enforcing method of constraint handler for pseudo solutions */
12411 static
12412 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12413 { /*lint --e{715}*/
12414  SCIP_Bool violated;
12415  int i;
12416 
12417  for( i = 0; i < nconss; i++ )
12418  {
12419  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12420  if( violated )
12421  {
12422  *result = SCIP_INFEASIBLE;
12423  return SCIP_OKAY;
12424  }
12425  }
12426  *result = SCIP_FEASIBLE;
12427 
12428  return SCIP_OKAY;
12429 }
12430 
12431 /** feasibility check method of constraint handler for integral solutions */
12432 static
12433 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12434 { /*lint --e{715}*/
12435  SCIP_Bool violated;
12436  int i;
12437 
12438  *result = SCIP_FEASIBLE;
12439 
12440  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12441  {
12442  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12443  if( violated )
12444  *result = SCIP_INFEASIBLE;
12445  }
12446 
12447  return SCIP_OKAY;
12448 }
12449 
12450 /** domain propagation method of constraint handler */
12451 static
12452 SCIP_DECL_CONSPROP(consPropKnapsack)
12453 { /*lint --e{715}*/
12454  SCIP_CONSHDLRDATA* conshdlrdata;
12455  SCIP_Bool cutoff;
12456  SCIP_Bool redundant;
12457  SCIP_Bool inpresolve;
12458  int nfixedvars;
12459  int i;
12461  cutoff = FALSE;
12462  nfixedvars = 0;
12463 
12464  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12465  assert(conshdlrdata != NULL);
12466 
12467  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12468  assert(!inpresolve || SCIPinProbing(scip));
12469 
12470  /* process useful constraints */
12471  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12472  {
12473  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12474  * otherwise the multi-aggregation should be resolved
12475  */
12476  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12477  continue;
12478 #ifndef NDEBUG
12479  else
12480  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12481 #endif
12482 
12483  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12484 
12485  /* unmark the constraint to be propagated */
12486  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12487  }
12488 
12489  /* adjust result code */
12490  if( cutoff )
12491  *result = SCIP_CUTOFF;
12492  else if( nfixedvars > 0 )
12493  *result = SCIP_REDUCEDDOM;
12494  else
12495  *result = SCIP_DIDNOTFIND;
12496 
12497  return SCIP_OKAY;
12498 }
12499 
12500 /** presolving method of constraint handler */
12501 static
12502 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12503 { /*lint --e{574,715}*/
12504  SCIP_CONSHDLRDATA* conshdlrdata;
12505  SCIP_CONSDATA* consdata;
12506  SCIP_CONS* cons;
12507  SCIP_Bool cutoff;
12508  SCIP_Bool redundant;
12509  SCIP_Bool success;
12510  int oldnfixedvars;
12511  int oldnchgbds;
12512  int oldndelconss;
12513  int oldnaddconss;
12514  int oldnchgcoefs;
12515  int oldnchgsides;
12516  int firstchange;
12517  int c;
12518  SCIP_Bool newchanges;
12519 
12520  /* remember old preprocessing counters */
12521  cutoff = FALSE;
12522  oldnfixedvars = *nfixedvars;
12523  oldnchgbds = *nchgbds;
12524  oldndelconss = *ndelconss;
12525  oldnaddconss = *naddconss;
12526  oldnchgcoefs = *nchgcoefs;
12527  oldnchgsides = *nchgsides;
12528  firstchange = INT_MAX;
12529 
12530  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12531 
12532  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12533  assert(conshdlrdata != NULL);
12534 
12535  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12536  {
12537  int thisnfixedvars;
12538  int thisnchgbds;
12539 
12540  cons = conss[c];
12541  consdata = SCIPconsGetData(cons);
12542  assert(consdata != NULL);
12543 
12544  /* update data structures */
12545  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12546  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12547  {
12548  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12549  if( cutoff )
12550  break;
12551  }
12552 
12553  /* force presolving the constraint in the initial round */
12554  if( nrounds == 0 )
12555  consdata->presolvedtiming = 0;
12556  else if( consdata->presolvedtiming >= presoltiming )
12557  continue;
12558 
12559  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12560  SCIPdebugPrintCons(scip, cons, NULL);
12561  consdata->presolvedtiming = presoltiming;
12562 
12563  thisnfixedvars = *nfixedvars;
12564  thisnchgbds = *nchgbds;
12565 
12566  /* merge constraint, so propagation works better */
12567  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12568  if( cutoff )
12569  break;
12570 
12571  /* add cliques in the knapsack to the clique table */
12572  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12573  {
12574  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12575  if( cutoff )
12576  break;
12577  }
12578 
12579  /* propagate constraint */
12580  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12581  {
12582  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12583 
12584  if( cutoff )
12585  break;
12586  if( redundant )
12587  {
12588  (*ndelconss)++;
12589  continue;
12590  }
12591  }
12592 
12593  /* remove again all fixed variables, if further fixings were found */
12594  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12595  {
12596  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12597  if( cutoff )
12598  break;
12599 
12600  thisnfixedvars = *nfixedvars;
12601  }
12602 
12603  if( !SCIPconsIsModifiable(cons) )
12604  {
12605  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12606  if( consdata->weightsum <= consdata->capacity )
12607  {
12608  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12609  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12610  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12611  continue;
12612  }
12613 
12614  /* divide weights by their greatest common divisor */
12615  normalizeWeights(cons, nchgcoefs, nchgsides);
12616 
12617  /* try to simplify inequalities */
12618  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12619  {
12620  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12621  if( cutoff )
12622  break;
12623 
12624  if( SCIPconsIsDeleted(cons) )
12625  continue;
12626 
12627  /* remove again all fixed variables, if further fixings were found */
12628  if( *nfixedvars > thisnfixedvars )
12629  {
12630  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12631  if( cutoff )
12632  break;
12633  }
12634  }
12635 
12636  /* tighten capacity and weights */
12637  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12638  if( cutoff )
12639  break;
12640 
12641  if( SCIPconsIsActive(cons) )
12642  {
12643  if( conshdlrdata->dualpresolving && SCIPallowDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12644  {
12645  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12646  * dual reduction
12647  */
12648  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12649  if( redundant )
12650  continue;
12651  }
12652 
12653  /* check if knapsack constraint is parallel to objective function */
12654  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12655  }
12656  }
12657  /* remember the first changed constraint to begin the next aggregation round with */
12658  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12659  firstchange = c;
12660  }
12661 
12662  /* preprocess pairs of knapsack constraints */
12663  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12664  {
12665  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12666  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12667  }
12668 
12669  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12670  success = TRUE;
12671  else
12672  success = FALSE;
12673 
12674  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12675  {
12676  SCIP_Longint npaircomparisons;
12677 
12678  npaircomparisons = 0;
12679  oldndelconss = *ndelconss;
12680  oldnchgsides = *nchgsides;
12681  oldnchgcoefs = *nchgcoefs;
12682 
12683  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12684  {
12685  cons = conss[c];
12686  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12687  continue;
12688 
12689  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12690 
12691  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12692 
12693  if( npaircomparisons > NMINCOMPARISONS )
12694  {
12695  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12696  success = TRUE;
12697  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12698  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12699  break;
12700  oldndelconss = *ndelconss;
12701  oldnchgsides = *nchgsides;
12702  oldnchgcoefs = *nchgcoefs;
12703  npaircomparisons = 0;
12704  }
12705  }
12706  }
12707 #ifdef WITH_CARDINALITY_UPGRADE
12708  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12709  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12710  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12711  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12712  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12713  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12714  * as well, we better keep this code disabled. */
12715  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12716  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12717  {
12718  SCIP_HASHMAP* varhash;
12719  SCIP_VAR** cardvars;
12720  SCIP_Real* cardweights;
12721  int noldupgdconss;
12722  int nscipvars;
12723  int makeupgrade;
12724 
12725  noldupgdconss = *nupgdconss;
12726  nscipvars = SCIPgetNVars(scip);
12727  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12728  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12729 
12730  /* set up hash map */
12731  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12732 
12733  /* We loop through all cardinality constraints twice:
12734  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12735  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12736  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12737  * - Second, upgrade knapsack constraints to cardinality constraints. */
12738  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12739  {
12740  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12741  {
12742  SCIP_CONS* cardcons;
12743  SCIP_VAR** vars;
12744  SCIP_Longint* weights;
12745  int nvars;
12746  int v;
12747 
12748  cons = conss[c];
12749  assert( cons != NULL );
12750  consdata = SCIPconsGetData(cons);
12751  assert( consdata != NULL );
12752 
12753  nvars = consdata->nvars;
12754  vars = consdata->vars;
12755  weights = consdata->weights;
12756 
12757  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12758  * - all variables must be binary (always true)
12759  * - all coefficients must be 1.0
12760  * - the right hand side must be smaller than nvars
12761  */
12762  if ( consdata->capacity >= nvars )
12763  continue;
12764 
12765  /* the weights are sorted: check first and last weight */
12766  assert( consdata->sorted );
12767  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12768  continue;
12769 
12770  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12771  for (v = 0; v < nvars; ++v)
12772  {
12773  SCIP_BOUNDTYPE* impltypes;
12774  SCIP_Real* implbounds;
12775  SCIP_VAR** implvars;
12776  SCIP_VAR* var;
12777  int nimpls;
12778  int j;
12779 
12780  var = consdata->vars[v];
12781  assert( var != NULL );
12782  assert( SCIPvarIsBinary(var) );
12783 
12784  /* ignore non-active variables */
12785  if ( ! SCIPvarIsActive(var) )
12786  break;
12787 
12788  /* be sure that implication variable has zero objective */
12789  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12790  break;
12791 
12792  nimpls = SCIPvarGetNImpls(var, FALSE);
12793  implvars = SCIPvarGetImplVars(var, FALSE);
12794  implbounds = SCIPvarGetImplBounds(var, FALSE);
12795  impltypes = SCIPvarGetImplTypes(var, FALSE);
12796 
12797  for (j = 0; j < nimpls; ++j)
12798  {
12799  /* be sure that continuous variable is fixed to 0 */
12800  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12801  continue;
12802 
12803  /* cannot currently deal with nonzero fixings */
12804  if ( ! SCIPisZero(scip, implbounds[j]) )
12805  continue;
12806 
12807  /* number of down locks should be one */
12808  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12809  continue;
12810 
12811  cardvars[v] = implvars[j];
12812  cardweights[v] = (SCIP_Real) v;
12813 
12814  break;
12815  }
12816 
12817  /* found no variable upper bound candidate -> exit */
12818  if ( j >= nimpls )
12819  break;
12820  }
12821 
12822  /* did not find fitting variable upper bound for some variable -> exit */
12823  if ( v < nvars )
12824  break;
12825 
12826  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12827  * in which the binary variable is involved in */
12828  if ( makeupgrade == 0 )
12829  {
12830  for (v = 0; v < nvars; ++v)
12831  {
12832  if ( SCIPhashmapExists(varhash, vars[v]) )
12833  {
12834  int image;
12835 
12836  image = (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]);
12837  SCIP_CALL( SCIPhashmapSetImage(varhash, vars[v], (void*) (size_t) (image + 1)) );/*lint !e776*/
12838  assert( image + 1 == (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) );
12839  }
12840  else
12841  {
12842  SCIP_CALL( SCIPhashmapInsert(varhash, vars[v], (void*) (size_t) 1) );/*lint !e571*/
12843  assert( 1 == (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) );
12844  assert( SCIPhashmapExists(varhash, vars[v]) );
12845  }
12846  }
12847  }
12848  else
12849  {
12850  SCIP_CONS* origcons;
12851 
12852  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12853  * knapsack constraint coincides with the number of variable up locks */
12854  for (v = 0; v < nvars; ++v)
12855  {
12856  assert( SCIPhashmapExists(varhash, vars[v]) );
12857  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) )
12858  break;
12859  }
12860  if ( v < nvars )
12861  break;
12862 
12863  /* store that we have upgraded */
12864  conshdlrdata->upgradedcard = TRUE;
12865 
12866  /* at this point we found suitable variable upper bounds */
12867  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12868 
12869  /* create cardinality constraint */
12870  assert( ! SCIPconsIsModifiable(cons) );
12871  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12875 #ifdef SCIP_DEBUG
12876  SCIPprintCons(scip, cons, NULL);
12877  SCIPinfoMessage(scip, NULL, "\n");
12878  SCIPprintCons(scip, cardcons, NULL);
12879  SCIPinfoMessage(scip, NULL, "\n");
12880 #endif
12881  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12882  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12883  ++(*nupgdconss);
12884 
12885  /* delete oknapsack constraint */
12886  SCIP_CALL( SCIPdelCons(scip, cons) );
12887  ++(*ndelconss);
12888 
12889  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12890  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12891  * although the cardinality constraint is satisfied. */
12892  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12893  assert( origcons != NULL );
12894  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12895 
12896  for (v = 0; v < nvars; ++v)
12897  {
12898  int image;
12899 
12900  assert ( SCIPhashmapExists(varhash, vars[v]) );
12901  image = (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]);
12902  SCIP_CALL( SCIPhashmapSetImage(varhash, vars[v], (void*) (size_t) (image - 1)) );
12903  assert( image - 1 == (int) (size_t) SCIPhashmapGetImage(varhash, vars[v]) );
12904  }
12905  }
12906  }
12907  }
12908  SCIPhashmapFree(&varhash);
12909  SCIPfreeBufferArray(scip, &cardweights);
12910  SCIPfreeBufferArray(scip, &cardvars);
12911 
12912  if ( *nupgdconss > noldupgdconss )
12913  success = TRUE;
12914  }
12915 #endif
12916 
12917  if( cutoff )
12918  *result = SCIP_CUTOFF;
12919  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12920  *result = SCIP_SUCCESS;
12921  else
12922  *result = SCIP_DIDNOTFIND;
12923 
12924  return SCIP_OKAY;
12925 }
12926 
12927 /** propagation conflict resolving method of constraint handler */
12928 static
12929 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12930 { /*lint --e{715}*/
12931  SCIP_CONSDATA* consdata;
12932  SCIP_Longint capsum;
12933  int i;
12934 
12935  assert(result != NULL);
12936 
12937  consdata = SCIPconsGetData(cons);
12938  assert(consdata != NULL);
12939 
12940  /* check if we fixed a binary variable to one (due to negated clique) */
12941  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12942  {
12943  for( i = 0; i < consdata->nvars; ++i )
12944  {
12945  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12946  {
12947  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12948  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12949  break;
12950  }
12951  }
12952  assert(i < consdata->nvars);
12953  }
12954  else
12955  {
12956  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12957  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12958  * knapsack constraint, see one above call of SCIPinferBinvarCons
12959  */
12960  if( inferinfo < 0 )
12961  capsum = 0;
12962  else
12963  {
12964  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12965  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12966  */
12967  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12968  capsum = consdata->weights[inferinfo];
12969  else
12970  {
12971  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12972  {}
12973  assert(i < consdata->nvars);
12974  capsum = consdata->weights[i];
12975  }
12976  }
12977 
12978  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12979  * the capacity
12980  */
12981  if( capsum <= consdata->capacity )
12982  {
12983  for( i = 0; i < consdata->nvars; i++ )
12984  {
12985  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12986  {
12987  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12988  capsum += consdata->weights[i];
12989  if( capsum > consdata->capacity )
12990  break;
12991  }
12992  }
12993  }
12994  }
12995 
12996  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12997  * to zero can included negated clique information. A negated clique means, that at most one of the clique
12998  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
12999  * used to fix variables to zero.
13000  *
13001  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13002  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13003  * one.
13004  */
13005  *result = SCIP_SUCCESS;
13006 
13007  return SCIP_OKAY;
13008 }
13009 
13010 /** variable rounding lock method of constraint handler */
13011 /**! [SnippetConsLockKnapsack] */
13012 static
13013 SCIP_DECL_CONSLOCK(consLockKnapsack)
13014 { /*lint --e{715}*/
13015  SCIP_CONSDATA* consdata;
13016  int i;
13017 
13018  consdata = SCIPconsGetData(cons);
13019  assert(consdata != NULL);
13020 
13021  for( i = 0; i < consdata->nvars; i++)
13022  {
13023  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13024  }
13025 
13026  return SCIP_OKAY;
13027 }
13028 /**! [SnippetConsLockKnapsack] */
13029 
13030 
13031 /** variable deletion method of constraint handler */
13032 static
13033 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13034 {
13035  assert(scip != NULL);
13036  assert(conshdlr != NULL);
13037  assert(conss != NULL || nconss == 0);
13038 
13039  if( nconss > 0 )
13040  {
13041  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13042  }
13043 
13044  return SCIP_OKAY;
13045 }
13046 
13047 /** constraint display method of constraint handler */
13048 static
13049 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13050 { /*lint --e{715}*/
13051  SCIP_CONSDATA* consdata;
13052  int i;
13053 
13054  assert( scip != NULL );
13055  assert( conshdlr != NULL );
13056  assert( cons != NULL );
13058  consdata = SCIPconsGetData(cons);
13059  assert(consdata != NULL);
13060 
13061  for( i = 0; i < consdata->nvars; ++i )
13062  {
13063  if( i > 0 )
13064  SCIPinfoMessage(scip, file, " ");
13065  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13066  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13067  }
13068  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13069 
13070  return SCIP_OKAY;
13071 }
13072 
13073 /** constraint copying method of constraint handler */
13074 static
13075 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13076 { /*lint --e{715}*/
13077  SCIP_VAR** sourcevars;
13078  SCIP_Longint* weights;
13079  SCIP_Real* coefs;
13080  const char* consname;
13081  int nvars;
13082  int v;
13084  /* get variables and coefficients of the source constraint */
13085  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13086  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13087  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13088 
13089  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13090  for( v = 0; v < nvars; ++v )
13091  coefs[v] = (SCIP_Real) weights[v];
13092 
13093  if( name != NULL )
13094  consname = name;
13095  else
13096  consname = SCIPconsGetName(sourcecons);
13097 
13098  /* copy the logic using the linear constraint copy method */
13099  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13100  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13101  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13102  assert(cons != NULL);
13103 
13104  SCIPfreeBufferArray(scip, &coefs);
13105 
13106  return SCIP_OKAY;
13107 }
13108 
13109 /** constraint parsing method of constraint handler */
13110 static
13111 SCIP_DECL_CONSPARSE(consParseKnapsack)
13112 { /*lint --e{715}*/
13113  SCIP_VAR* var;
13114  SCIP_Longint weight;
13115  SCIP_VAR** vars;
13116  SCIP_Longint* weights;
13117  SCIP_Longint capacity;
13118  char* endptr;
13119  int nread;
13120  int nvars;
13121  int varssize;
13122 
13123  assert(scip != NULL);
13124  assert(success != NULL);
13125  assert(str != NULL);
13126  assert(name != NULL);
13127  assert(cons != NULL);
13128 
13129  *success = TRUE;
13130 
13131  nvars = 0;
13132  varssize = 5;
13133  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13134  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13135 
13136  while( *str != '\0' )
13137  {
13138  /* try to parse coefficient, and stop if not successful (probably reached <=) */
13139  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13140  break;
13141 
13142  str += nread;
13143 
13144  /* skip whitespace */
13145  while( isspace((int)*str) )
13146  ++str;
13147 
13148  /* parse variable name */
13149  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13150  if( var == NULL )
13151  {
13152  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13153  *success = FALSE;
13154  break;
13155  }
13156 
13157  str = endptr;
13158 
13159  /* store weight and variable */
13160  if( varssize <= nvars )
13161  {
13162  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13163  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13164  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13165  }
13166 
13167  vars[nvars] = var;
13168  weights[nvars] = weight;
13169  ++nvars;
13170 
13171  /* skip whitespace */
13172  while( isspace((int)*str) )
13173  ++str;
13174  }
13175 
13176  if( *success )
13177  {
13178  if( strncmp(str, "<= ", 3) != 0 )
13179  {
13180  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13181  *success = FALSE;
13182  }
13183  else
13184  {
13185  str += 3;
13186  }
13187  }
13188 
13189  if( *success )
13190  {
13191  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13192  {
13193  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13194  *success = FALSE;
13195  }
13196  else
13197  {
13198  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13199  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13200  }
13201  }
13202 
13203  SCIPfreeBufferArray(scip, &vars);
13204  SCIPfreeBufferArray(scip, &weights);
13205 
13206  return SCIP_OKAY;
13207 }
13208 
13209 /** constraint method of constraint handler which returns the variables (if possible) */
13210 static
13211 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13212 { /*lint --e{715}*/
13213  SCIP_CONSDATA* consdata;
13214 
13215  consdata = SCIPconsGetData(cons);
13216  assert(consdata != NULL);
13217 
13218  if( varssize < consdata->nvars )
13219  (*success) = FALSE;
13220  else
13221  {
13222  assert(vars != NULL);
13223 
13224  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13225  (*success) = TRUE;
13226  }
13227 
13228  return SCIP_OKAY;
13229 }
13230 
13231 /** constraint method of constraint handler which returns the number of variables (if possible) */
13232 static
13233 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13234 { /*lint --e{715}*/
13235  SCIP_CONSDATA* consdata;
13236 
13237  consdata = SCIPconsGetData(cons);
13238  assert(consdata != NULL);
13239 
13240  (*nvars) = consdata->nvars;
13241  (*success) = TRUE;
13242 
13243  return SCIP_OKAY;
13244 }
13245 
13246 /*
13247  * Event handler
13248  */
13249 
13250 /** execution method of bound change event handler */
13251 static
13252 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13253 { /*lint --e{715}*/
13254  SCIP_CONSDATA* consdata;
13255 
13256  assert(eventdata != NULL);
13257  assert(eventdata->cons != NULL);
13258 
13259  consdata = SCIPconsGetData(eventdata->cons);
13260  assert(consdata != NULL);
13261 
13262  switch( SCIPeventGetType(event) )
13263  {
13265  consdata->onesweightsum += eventdata->weight;
13266  consdata->presolvedtiming = 0;
13267  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13268  break;
13270  consdata->onesweightsum -= eventdata->weight;
13271  break;
13273  consdata->presolvedtiming = 0;
13274  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13275  break;
13276  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13277  if( !consdata->existmultaggr )
13278  {
13279  SCIP_VAR* var;
13280  var = SCIPeventGetVar(event);
13281  assert(var != NULL);
13282 
13283  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13285  {
13286  consdata->existmultaggr = TRUE;
13287  consdata->merged = FALSE;
13288  }
13289  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13291  consdata->merged = FALSE;
13292  }
13293  /*lint -fallthrough*/
13294  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13295  consdata->presolvedtiming = 0;
13296  break;
13298  consdata->varsdeleted = TRUE;
13299  break;
13300  default:
13301  SCIPerrorMessage("invalid event type %x\n", SCIPeventGetType(event));
13302  return SCIP_INVALIDDATA;
13303  }
13304 
13305  return SCIP_OKAY;
13306 }
13307 
13308 
13309 /*
13310  * constraint specific interface methods
13311  */
13312 
13313 /** creates the handler for knapsack constraints and includes it in SCIP */
13315  SCIP* scip /**< SCIP data structure */
13316  )
13317 {
13318  SCIP_EVENTHDLRDATA* eventhdlrdata;
13319  SCIP_CONSHDLRDATA* conshdlrdata;
13320  SCIP_CONSHDLR* conshdlr;
13321 
13322  /* create knapsack constraint handler data */
13323  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13324 
13325  /* include event handler for bound change events */
13326  eventhdlrdata = NULL;
13327  conshdlrdata->eventhdlr = NULL;
13328  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13329  eventExecKnapsack, eventhdlrdata) );
13330 
13331  /* get event handler for bound change events */
13332  if( conshdlrdata->eventhdlr == NULL )
13333  {
13334  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13335  return SCIP_PLUGINNOTFOUND;
13336  }
13337 
13338  /* include constraint handler */
13341  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13342  conshdlrdata) );
13343 
13344  assert(conshdlr != NULL);
13345 
13346  /* set non-fundamental callbacks via specific setter functions */
13347  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13348  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13349  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13350  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13351  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13352  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13353  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13354  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13355  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13356  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13357  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13358  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13359  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13360  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13361  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13362  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13364  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13365  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13367  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13368  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13369 
13370  if( SCIPfindConshdlr(scip,"linear") != NULL )
13371  {
13372  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13374  }
13375 
13376  /* add knapsack constraint handler parameters */
13377  SCIP_CALL( SCIPaddIntParam(scip,
13378  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13379  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13380  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13382  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13383  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13384  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13386  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13387  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13388  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13389  SCIP_CALL( SCIPaddIntParam(scip,
13390  "constraints/" CONSHDLR_NAME "/maxrounds",
13391  "maximal number of separation rounds per node (-1: unlimited)",
13392  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13393  SCIP_CALL( SCIPaddIntParam(scip,
13394  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13395  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13396  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13397  SCIP_CALL( SCIPaddIntParam(scip,
13398  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13399  "maximal number of cuts separated per separation round",
13400  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13401  SCIP_CALL( SCIPaddIntParam(scip,
13402  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13403  "maximal number of cuts separated per separation round in the root node",
13404  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13406  "constraints/" CONSHDLR_NAME "/disaggregation",
13407  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13408  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13410  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13411  "should presolving try to simplify knapsacks",
13412  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13414  "constraints/" CONSHDLR_NAME "/negatedclique",
13415  "should negated clique information be used in solving process",
13416  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13418  "constraints/" CONSHDLR_NAME "/presolpairwise",
13419  "should pairwise constraint comparison be performed in presolving?",
13420  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13422  "constraints/" CONSHDLR_NAME "/presolusehashing",
13423  "should hash table be used for detecting redundant constraints in advance",
13424  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13426  "constraints/" CONSHDLR_NAME "/dualpresolving",
13427  "should dual presolving steps be performed?",
13428  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13430  "constraints/" CONSHDLR_NAME "/usegubs",
13431  "should GUB information be used for separation?",
13432  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13434  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13435  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13436  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13438  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13439  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13440  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13442  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13443  "should clique partition information be updated when old partition seems outdated?",
13444  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13446  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13447  "factor on the growth of global cliques to decide when to update a previous "
13448  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13449  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13450 #ifdef WITH_CARDINALITY_UPGRADE
13452  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13453  "if TRUE then try to update knapsack constraints to cardinality constraints",
13454  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13455 #endif
13456  return SCIP_OKAY;
13457 }
13458 
13459 /** creates and captures a knapsack constraint
13460  *
13461  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13462  */
13463 /**! [SnippetConsCreationKnapsack] */
13465  SCIP* scip, /**< SCIP data structure */
13466  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13467  const char* name, /**< name of constraint */
13468  int nvars, /**< number of items in the knapsack */
13469  SCIP_VAR** vars, /**< array with item variables */
13470  SCIP_Longint* weights, /**< array with item weights */
13471  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13472  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13473  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13474  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13475  * Usually set to TRUE. */
13476  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13477  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13478  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13479  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13480  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13481  * Usually set to TRUE. */
13482  SCIP_Bool local, /**< is constraint only valid locally?
13483  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13484  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13485  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13486  * adds coefficients to this constraint. */
13487  SCIP_Bool dynamic, /**< is constraint subject to aging?
13488  * Usually set to FALSE. Set to TRUE for own cuts which
13489  * are separated as constraints. */
13490  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13491  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13492  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13493  * if it may be moved to a more global node?
13494  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13495  )
13496 {
13497  SCIP_CONSHDLRDATA* conshdlrdata;
13498  SCIP_CONSHDLR* conshdlr;
13499  SCIP_CONSDATA* consdata;
13500 
13501  /* find the knapsack constraint handler */
13502  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13503  if( conshdlr == NULL )
13504  {
13505  SCIPerrorMessage("knapsack constraint handler not found\n");
13506  return SCIP_PLUGINNOTFOUND;
13507  }
13508 
13509  /* get event handler */
13510  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13511  assert(conshdlrdata != NULL);
13512  assert(conshdlrdata->eventhdlr != NULL);
13513 
13514  /* create constraint data */
13515  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13516 
13517  /* create constraint */
13518  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13519  local, modifiable, dynamic, removable, stickingatnode) );
13520 
13521  /* catch events for variables */
13522  if( SCIPisTransformed(scip) )
13523  {
13524  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13525  }
13526 
13527  return SCIP_OKAY;
13528 }
13529 /**! [SnippetConsCreationKnapsack] */
13530 
13531 /** creates and captures a knapsack constraint
13532  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13533  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13534  *
13535  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13536  *
13537  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13538  */
13540  SCIP* scip, /**< SCIP data structure */
13541  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13542  const char* name, /**< name of constraint */
13543  int nvars, /**< number of items in the knapsack */
13544  SCIP_VAR** vars, /**< array with item variables */
13545  SCIP_Longint* weights, /**< array with item weights */
13546  SCIP_Longint capacity /**< capacity of knapsack */
13547  )
13548 {
13549  assert(scip != NULL);
13550 
13551  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13552  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13553 
13554  return SCIP_OKAY;
13555 }
13556 
13557 /** adds new item to knapsack constraint */
13559  SCIP* scip, /**< SCIP data structure */
13560  SCIP_CONS* cons, /**< constraint data */
13561  SCIP_VAR* var, /**< item variable */
13562  SCIP_Longint weight /**< item weight */
13563  )
13564 {
13565  assert(var != NULL);
13567  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13568  {
13569  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13570  return SCIP_INVALIDDATA;
13571  }
13572 
13573  SCIP_CALL( addCoef(scip, cons, var, weight) );
13574 
13575  return SCIP_OKAY;
13576 }
13577 
13578 /** gets the capacity of the knapsack constraint */
13580  SCIP* scip, /**< SCIP data structure */
13581  SCIP_CONS* cons /**< constraint data */
13582  )
13583 {
13584  SCIP_CONSDATA* consdata;
13585 
13586  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13587  {
13588  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13589  SCIPABORT();
13590  return 0; /*lint !e527*/
13591  }
13592 
13593  consdata = SCIPconsGetData(cons);
13594  assert(consdata != NULL);
13595 
13596  return consdata->capacity;
13597 }
13598 
13599 /** changes capacity of the knapsack constraint
13600  *
13601  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13602  */
13604  SCIP* scip, /**< SCIP data structure */
13605  SCIP_CONS* cons, /**< constraint data */
13606  SCIP_Longint capacity /**< new capacity of knapsack */
13607  )
13608 {
13609  SCIP_CONSDATA* consdata;
13610 
13612  {
13613  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13614  return SCIP_INVALIDDATA;
13615  }
13616 
13617  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13618  {
13619  SCIPerrorMessage("method can only be called during problem creation stage\n");
13620  return SCIP_INVALIDDATA;
13621  }
13622 
13623  consdata = SCIPconsGetData(cons);
13624  assert(consdata != NULL);
13625 
13626  consdata->capacity = capacity;
13627 
13628  return SCIP_OKAY;
13629 }
13630 
13631 /** gets the number of items in the knapsack constraint */
13633  SCIP* scip, /**< SCIP data structure */
13634  SCIP_CONS* cons /**< constraint data */
13635  )
13636 {
13637  SCIP_CONSDATA* consdata;
13638 
13639  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13640  {
13641  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13642  SCIPABORT();
13643  return -1; /*lint !e527*/
13644  }
13645 
13646  consdata = SCIPconsGetData(cons);
13647  assert(consdata != NULL);
13648 
13649  return consdata->nvars;
13650 }
13651 
13652 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13654  SCIP* scip, /**< SCIP data structure */
13655  SCIP_CONS* cons /**< constraint data */
13656  )
13657 {
13658  SCIP_CONSDATA* consdata;
13659 
13660  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13661  {
13662  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13663  SCIPABORT();
13664  return NULL; /*lint !e527*/
13665  }
13666 
13667  consdata = SCIPconsGetData(cons);
13668  assert(consdata != NULL);
13669 
13670  return consdata->vars;
13671 }
13672 
13673 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13675  SCIP* scip, /**< SCIP data structure */
13676  SCIP_CONS* cons /**< constraint data */
13677  )
13678 {
13679  SCIP_CONSDATA* consdata;
13680 
13681  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13682  {
13683  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13684  SCIPABORT();
13685  return NULL; /*lint !e527*/
13686  }
13687 
13688  consdata = SCIPconsGetData(cons);
13689  assert(consdata != NULL);
13690 
13691  return consdata->weights;
13692 }
13693 
13694 /** gets the dual solution of the knapsack constraint in the current LP */
13696  SCIP* scip, /**< SCIP data structure */
13697  SCIP_CONS* cons /**< constraint data */
13698  )
13699 {
13700  SCIP_CONSDATA* consdata;
13701 
13702  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13703  {
13704  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13705  SCIPABORT();
13706  return SCIP_INVALID; /*lint !e527*/
13707  }
13708 
13709  consdata = SCIPconsGetData(cons);
13710  assert(consdata != NULL);
13711 
13712  if( consdata->row != NULL )
13713  return SCIProwGetDualsol(consdata->row);
13714  else
13715  return 0.0;
13716 }
13717 
13718 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13720  SCIP* scip, /**< SCIP data structure */
13721  SCIP_CONS* cons /**< constraint data */
13722  )
13723 {
13724  SCIP_CONSDATA* consdata;
13725 
13726  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13727  {
13728  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13729  SCIPABORT();
13730  return SCIP_INVALID; /*lint !e527*/
13731  }
13732 
13733  consdata = SCIPconsGetData(cons);
13734  assert(consdata != NULL);
13735 
13736  if( consdata->row != NULL )
13737  return SCIProwGetDualfarkas(consdata->row);
13738  else
13739  return 0.0;
13740 }
13741 
13742 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13743  * the user must not modify the row!
13744  */
13746  SCIP* scip, /**< SCIP data structure */
13747  SCIP_CONS* cons /**< constraint data */
13748  )
13749 {
13750  SCIP_CONSDATA* consdata;
13751 
13752  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13753  {
13754  SCIPerrorMessage("constraint is not a knapsack\n");
13755  SCIPABORT();
13756  return NULL; /*lint !e527*/
13757  }
13758 
13759  consdata = SCIPconsGetData(cons);
13760  assert(consdata != NULL);
13761 
13762  return consdata->row;
13763 }
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:17557
#define NULL
Definition: def.h:239
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:10958
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:5120
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:412
#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:17135
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)
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:2265
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:17535
#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:17343
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:11789
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
#define SCIP_MAXSTRLEN
Definition: def.h:260
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:17123
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1602
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:17399
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:17706
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:16909
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:65
#define MAX_CLIQUELENGTH
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10325
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:10017
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:64
#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:17577
SCIP_RETCODE SCIPsolveKnapsackApproximately(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17036
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:5236
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:17547
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)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_LONGINT_MAX
Definition: def.h:136
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:611
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:16889
#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:17695
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:2014
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:17159
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17080
#define DEFAULT_SEPACARDFREQ
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4199
#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:6819
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:17353
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11697
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:648
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:4375
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:17609
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:16729
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:2826
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:174
#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:351
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:474
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:17567
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17147
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:2395
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:17599
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)
void SCIPsortDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, int len)
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:9114
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:17653
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:62
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:17621
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:7154
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8096
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11422
#define MIN(x, y)
Definition: def.h:209
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:17191
#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:484
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8168
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:80
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:16902
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4290
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:2326
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17111
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:17667
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:287
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:2064
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:17638
#define SCIP_LONGINT_FORMAT
Definition: def.h:142
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:208
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:8478
#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:7473
#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_RETCODE SCIPhashmapSetImage(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2971
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16848
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7373
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:150
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:739
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:11757
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:170
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8255
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2094
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17589
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:135
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:8887
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17026
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:17409
#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:16871
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
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
#define USESUPADDLIFT
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:419
#define NMINCOMPARISONS
static SCIP_DECL_CONSTRANS(consTransKnapsack)
SCIP_Real SCIPgetDualfarkasKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:530
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPABORT()
Definition: def.h:323
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:8454
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:16950
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:5636
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:17016
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:16884
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