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 2002-2022 Zuse Institute Berlin */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cons_knapsack.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief Constraint handler for knapsack constraints of the form \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
28  * @author Tobias Achterberg
29  * @author Xin Liu
30  * @author Kati Wolter
31  * @author Michael Winkler
32  * @author Tobias Fischer
33  */
34 
35 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36 
37 #include "blockmemshell/memory.h"
38 #include "scip/cons_knapsack.h"
39 #include "scip/cons_linear.h"
40 #include "scip/cons_logicor.h"
41 #include "scip/cons_setppc.h"
42 #include "scip/pub_cons.h"
43 #include "scip/pub_event.h"
44 #include "scip/pub_implics.h"
45 #include "scip/pub_lp.h"
46 #include "scip/pub_message.h"
47 #include "scip/pub_misc.h"
48 #include "scip/pub_misc_select.h"
49 #include "scip/pub_misc_sort.h"
50 #include "scip/pub_sepa.h"
51 #include "scip/pub_var.h"
52 #include "scip/scip_branch.h"
53 #include "scip/scip_conflict.h"
54 #include "scip/scip_cons.h"
55 #include "scip/scip_copy.h"
56 #include "scip/scip_cut.h"
57 #include "scip/scip_event.h"
58 #include "scip/scip_general.h"
59 #include "scip/scip_lp.h"
60 #include "scip/scip_mem.h"
61 #include "scip/scip_message.h"
62 #include "scip/scip_nlp.h"
63 #include "scip/scip_numerics.h"
64 #include "scip/scip_param.h"
65 #include "scip/scip_prob.h"
66 #include "scip/scip_probing.h"
67 #include "scip/scip_sol.h"
68 #include "scip/scip_solvingstats.h"
69 #include "scip/scip_tree.h"
70 #include "scip/scip_var.h"
71 #include <ctype.h>
72 #include <string.h>
73 
74 #ifdef WITH_CARDINALITY_UPGRADE
75 #include "scip/cons_cardinality.h"
76 #endif
77 
78 /* constraint handler properties */
79 #define CONSHDLR_NAME "knapsack"
80 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
81 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
82 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
83 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
84 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
85 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
86 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
87  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
88 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
89 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
90 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
91 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
92 
93 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
94 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
95 
96 #define EVENTHDLR_NAME "knapsack"
97 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
98 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
99  | SCIP_EVENTTYPE_UBTIGHTENED \
100  | SCIP_EVENTTYPE_VARFIXED \
101  | SCIP_EVENTTYPE_VARDELETED \
102  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
103 
104 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
106 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
107 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
109 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
110 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
111 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
113 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
114 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
115 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
116 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
117 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
118 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
119  * to best node's dual bound for separating knapsack cuts */
120 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
121 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
122 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
124 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
125 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
127 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
128 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
130 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
131 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
132 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
133  * comparison round */
134 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
135 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
136  * function defining an upper bound and prevent these constraints from
137  * entering the LP */
138 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
139  * function defining a lower bound and prevent these constraints from
140  * entering the LP */
141 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
142 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
144 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
145 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
146 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
147 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
148  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
149 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
150 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
151 #ifdef WITH_CARDINALITY_UPGRADE
152 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
153 #endif
155 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
156 
157 /*
158  * Data structures
159  */
160 
161 /** constraint handler data */
162 struct SCIP_ConshdlrData
163 {
164  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
165  * you have to clear it at the end, exists only in presolving stage */
166  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167  * you have to clear it at the end, exists only in presolving stage */
168  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169  * you have to clear it at the end, exists only in presolving stage */
170  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
171  * you have to clear it at the end, exists only in presolving stage */
172  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
173  * you have to clear it at the end, exists only in presolving stage */
174  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
175  * you have to clear it at the end, exists only in presolving stage */
176  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
177  * you have to clear it at the end, exists only in presolving stage */
178  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
179  * you have to clear it at the end, exists only in presolving stage */
180  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
181  * you have to clear it at the end */
182  int ints1size; /**< size of ints1 array */
183  int ints2size; /**< size of ints2 array */
184  int longints1size; /**< size of longints1 array */
185  int longints2size; /**< size of longints2 array */
186  int bools1size; /**< size of bools1 array */
187  int bools2size; /**< size of bools2 array */
188  int bools3size; /**< size of bools3 array */
189  int bools4size; /**< size of bools4 array */
190  int reals1size; /**< size of reals1 array */
191  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
192  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
193  * to best node's dual bound for separating knapsack cuts */
194  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
195  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
196  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
197  int maxsepacuts; /**< maximal number of cuts separated per separation round */
198  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
199  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
200  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
201  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
202  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
203  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
204  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
205  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
206  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
207  * function defining an upper bound and prevent these constraints from
208  * entering the LP */
209  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
210  * function defining a lower bound and prevent these constraints from
211  * entering the LP */
212  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
213  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
214  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
215  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
216 #ifdef WITH_CARDINALITY_UPGRADE
217  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
218  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
219 #endif
220 };
221 
222 
223 /** constraint data for knapsack constraints */
224 struct SCIP_ConsData
225 {
226  SCIP_VAR** vars; /**< variables in knapsack constraint */
227  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
228  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
229  int* cliquepartition; /**< clique indices of the clique partition */
230  int* negcliquepartition; /**< clique indices of the negated clique partition */
231  SCIP_ROW* row; /**< corresponding LP row */
232  SCIP_NLROW* nlrow; /**< corresponding NLP row */
233  int nvars; /**< number of variables in knapsack constraint */
234  int varssize; /**< size of vars, weights, and eventdata arrays */
235  int ncliques; /**< number of cliques in the clique partition */
236  int nnegcliques; /**< number of cliques in the negated clique partition */
237  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
238  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
239  SCIP_Longint capacity; /**< capacity of knapsack */
240  SCIP_Longint weightsum; /**< sum of all weights */
241  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
242  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
243  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
244  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
245  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
246  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
247  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
248  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
249  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
250 };
251 
252 /** event data for bound changes events */
253 struct SCIP_EventData
254 {
255  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
256  SCIP_Longint weight; /**< weight of variable */
257  int filterpos; /**< position of event in variable's event filter */
258 };
259 
260 
261 /** data structure to combine two sorting key values */
262 struct sortkeypair
263 {
264  SCIP_Real key1; /**< first sort key value */
265  SCIP_Real key2; /**< second sort key value */
266 };
267 typedef struct sortkeypair SORTKEYPAIR;
268 
269 /** status of GUB constraint */
270 enum GUBVarstatus
271 {
272  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
273  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
274  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
275  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
276  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
277  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
278 };
279 typedef enum GUBVarstatus GUBVARSTATUS;
281 /** status of variable in GUB constraint */
283 {
284  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
285  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
286  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
287  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
288  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
289  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
290 };
291 typedef enum GUBConsstatus GUBCONSSTATUS;
293 /** data structure of GUB constraints */
295 {
296  int* gubvars; /**< indices of GUB variables in knapsack constraint */
297  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
298  int ngubvars; /**< number of GUB variables */
299  int gubvarssize; /**< size of gubvars array */
300 };
301 typedef struct SCIP_GUBCons SCIP_GUBCONS;
303 /** data structure of a set of GUB constraints */
305 {
306  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
307  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
308  int ngubconss; /**< number of GUB constraints */
309  int nvars; /**< number of variables in knapsack constraint */
310  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
311  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
312 };
313 typedef struct SCIP_GUBSet SCIP_GUBSET;
315 /*
316  * Local methods
317  */
319 /** comparison method for two sorting key pairs */
320 static
321 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
322 {
323  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
324  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
325 
326  if( sortkeypair1->key1 < sortkeypair2->key1 )
327  return -1;
328  else if( sortkeypair1->key1 > sortkeypair2->key1 )
329  return +1;
330  else if( sortkeypair1->key2 < sortkeypair2->key2 )
331  return -1;
332  else if( sortkeypair1->key2 > sortkeypair2->key2 )
333  return +1;
334  else
335  return 0;
336 }
337 
338 /** creates event data */
339 static
341  SCIP* scip, /**< SCIP data structure */
342  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
343  SCIP_CONS* cons, /**< constraint */
344  SCIP_Longint weight /**< weight of variable */
345  )
346 {
347  assert(eventdata != NULL);
349  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
350  (*eventdata)->cons = cons;
351  (*eventdata)->weight = weight;
352 
353  return SCIP_OKAY;
354 }
355 
356 /** frees event data */
357 static
359  SCIP* scip, /**< SCIP data structure */
360  SCIP_EVENTDATA** eventdata /**< pointer to event data */
361  )
362 {
363  assert(eventdata != NULL);
364 
365  SCIPfreeBlockMemory(scip, eventdata);
367  return SCIP_OKAY;
368 }
369 
370 /** sorts items in knapsack with nonincreasing weights */
371 static
372 void sortItems(
373  SCIP_CONSDATA* consdata /**< constraint data */
374  )
375 {
376  assert(consdata != NULL);
377  assert(consdata->nvars == 0 || consdata->vars != NULL);
378  assert(consdata->nvars == 0 || consdata->weights != NULL);
379  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
380  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
381 
382  if( !consdata->sorted )
383  {
384  int pos;
385  int lastcliquenum;
386  int v;
387 
388  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
389  * sorted by first array in non-increasing order via sort template */
391  consdata->weights,
392  (void**)consdata->vars,
393  (void**)consdata->eventdata,
394  consdata->cliquepartition,
395  consdata->negcliquepartition,
396  consdata->nvars);
397 
398  v = consdata->nvars - 1;
399  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
400  while( v >= 0 )
401  {
402  int w = v - 1;
403 
404  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
405  --w;
406 
407  if( v - w > 1 )
408  {
409  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
411  (void**)(&(consdata->vars[w+1])),
412  (void**)(&(consdata->eventdata[w+1])),
413  &(consdata->cliquepartition[w+1]),
414  &(consdata->negcliquepartition[w+1]),
415  SCIPvarComp,
416  v - w);
417  }
418  v = w;
419  }
420 
421  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
422  if( consdata->cliquepartitioned )
423  {
424  lastcliquenum = 0;
425 
426  for( pos = 0; pos < consdata->nvars; ++pos )
427  {
428  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
429  * partition is invalid */
430  if( consdata->cliquepartition[pos] > lastcliquenum )
431  {
432  consdata->cliquepartitioned = FALSE;
433  break;
434  }
435  else if( consdata->cliquepartition[pos] == lastcliquenum )
436  ++lastcliquenum;
437  }
438  }
439  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
440  if( consdata->negcliquepartitioned )
441  {
442  lastcliquenum = 0;
443 
444  for( pos = 0; pos < consdata->nvars; ++pos )
445  {
446  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
447  * partition is invalid */
448  if( consdata->negcliquepartition[pos] > lastcliquenum )
449  {
450  consdata->negcliquepartitioned = FALSE;
451  break;
452  }
453  else if( consdata->negcliquepartition[pos] == lastcliquenum )
454  ++lastcliquenum;
455  }
456  }
457 
458  consdata->sorted = TRUE;
459  }
460 #ifndef NDEBUG
461  {
462  /* check if the weight array is sorted in a non-increasing way */
463  int i;
464  for( i = 0; i < consdata->nvars-1; ++i )
465  assert(consdata->weights[i] >= consdata->weights[i+1]);
466  }
467 #endif
468 }
469 
470 /** calculates a partition of the variables into cliques */
471 static
473  SCIP* scip, /**< SCIP data structure */
474  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
475  SCIP_CONSDATA* consdata, /**< constraint data */
476  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
477  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
478  )
479 {
480  SCIP_Bool ispartitionoutdated;
481  SCIP_Bool isnegpartitionoutdated;
482  assert(consdata != NULL);
483  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
484 
485  /* rerun eventually if number of global cliques increased considerably since last partition */
486  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
487  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
488 
489  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
490  {
491  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
492  consdata->cliquepartitioned = TRUE;
493  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
494  }
495 
496  /* rerun eventually if number of global cliques increased considerably since last negated partition */
497  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
498  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
499 
500  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
501  {
502  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
503  consdata->negcliquepartitioned = TRUE;
504  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
505  }
506  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
507  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
508 
509  return SCIP_OKAY;
510 }
511 
512 /** installs rounding locks for the given variable in the given knapsack constraint */
513 static
515  SCIP* scip, /**< SCIP data structure */
516  SCIP_CONS* cons, /**< knapsack constraint */
517  SCIP_VAR* var /**< variable of constraint entry */
518  )
519 {
520  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
521 
522  return SCIP_OKAY;
523 }
524 
525 /** removes rounding locks for the given variable in the given knapsack constraint */
526 static
528  SCIP* scip, /**< SCIP data structure */
529  SCIP_CONS* cons, /**< knapsack constraint */
530  SCIP_VAR* var /**< variable of constraint entry */
531  )
532 {
533  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
534 
535  return SCIP_OKAY;
536 }
537 
538 /** catches bound change events for variables in knapsack */
539 static
541  SCIP* scip, /**< SCIP data structure */
542  SCIP_CONS* cons, /**< constraint */
543  SCIP_CONSDATA* consdata, /**< constraint data */
544  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
545  )
546 {
547  int i;
549  assert(cons != NULL);
550  assert(consdata != NULL);
551  assert(consdata->nvars == 0 || consdata->vars != NULL);
552  assert(consdata->nvars == 0 || consdata->weights != NULL);
553  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
554 
555  for( i = 0; i < consdata->nvars; i++)
556  {
557  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
558  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
559  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
560  }
561 
562  return SCIP_OKAY;
563 }
564 
565 /** drops bound change events for variables in knapsack */
566 static
568  SCIP* scip, /**< SCIP data structure */
569  SCIP_CONSDATA* consdata, /**< constraint data */
570  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
571  )
572 {
573  int i;
574 
575  assert(consdata != NULL);
576  assert(consdata->nvars == 0 || consdata->vars != NULL);
577  assert(consdata->nvars == 0 || consdata->weights != NULL);
578  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
579 
580  for( i = 0; i < consdata->nvars; i++)
581  {
582  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
583  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
584  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
585  }
586 
587  return SCIP_OKAY;
588 }
589 
590 /** ensures, that vars and vals arrays can store at least num entries */
591 static
593  SCIP* scip, /**< SCIP data structure */
594  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
595  int num, /**< minimum number of entries to store */
596  SCIP_Bool transformed /**< is constraint from transformed problem? */
597  )
598 {
599  assert(consdata != NULL);
600  assert(consdata->nvars <= consdata->varssize);
601 
602  if( num > consdata->varssize )
603  {
604  int newsize;
605 
606  newsize = SCIPcalcMemGrowSize(scip, num);
607  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
608  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
609  if( transformed )
610  {
611  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
612  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
613  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
614  }
615  else
616  {
617  assert(consdata->eventdata == NULL);
618  assert(consdata->cliquepartition == NULL);
619  assert(consdata->negcliquepartition == NULL);
620  }
621  consdata->varssize = newsize;
622  }
623  assert(num <= consdata->varssize);
624 
625  return SCIP_OKAY;
626 }
627 
628 /** updates all weight sums for fixed and unfixed variables */
629 static
630 void updateWeightSums(
631  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
632  SCIP_VAR* var, /**< variable for this weight */
633  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
634  )
635 {
636  assert(consdata != NULL);
637  assert(var != NULL);
639  consdata->weightsum += weightdelta;
640 
641  if( SCIPvarGetLbLocal(var) > 0.5 )
642  consdata->onesweightsum += weightdelta;
643 
644  assert(consdata->weightsum >= 0);
645  assert(consdata->onesweightsum >= 0);
646 }
647 
648 /** creates knapsack constraint data */
649 static
651  SCIP* scip, /**< SCIP data structure */
652  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
653  int nvars, /**< number of variables in knapsack */
654  SCIP_VAR** vars, /**< variables of knapsack */
655  SCIP_Longint* weights, /**< weights of knapsack items */
656  SCIP_Longint capacity /**< capacity of knapsack */
657  )
658 {
659  int v;
660  SCIP_Longint constant;
661 
662  assert(consdata != NULL);
663 
664  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
665 
666  constant = 0L;
667  (*consdata)->vars = NULL;
668  (*consdata)->weights = NULL;
669  (*consdata)->nvars = 0;
670  if( nvars > 0 )
671  {
672  SCIP_VAR** varsbuffer;
673  SCIP_Longint* weightsbuffer;
674  int k;
675 
676  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
677  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
678 
679  k = 0;
680  for( v = 0; v < nvars; ++v )
681  {
682  assert(vars[v] != NULL);
683  assert(SCIPvarIsBinary(vars[v]));
684 
685  /* all weight have to be non negative */
686  assert( weights[v] >= 0 );
687 
688  if( weights[v] > 0 )
689  {
690  /* treat fixed variables as constants if problem compression is enabled */
691  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
692  {
693  /* only if the variable is fixed to 1, we add its weight to the constant */
694  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
695  constant += weights[v];
696  }
697  else
698  {
699  varsbuffer[k] = vars[v];
700  weightsbuffer[k] = weights[v];
701  ++k;
702  }
703  }
704  }
705  assert(k >= 0);
706  assert(constant >= 0);
707 
708  (*consdata)->nvars = k;
709 
710  /* copy the active variables and weights into the constraint data structure */
711  if( k > 0 )
712  {
713  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
714  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
715  }
716 
717  /* free buffer storage */
718  SCIPfreeBufferArray(scip, &weightsbuffer);
719  SCIPfreeBufferArray(scip, &varsbuffer);
720  }
721 
722  (*consdata)->varssize = (*consdata)->nvars;
723  (*consdata)->capacity = capacity - constant;
724  (*consdata)->eventdata = NULL;
725  (*consdata)->cliquepartition = NULL;
726  (*consdata)->negcliquepartition = NULL;
727  (*consdata)->row = NULL;
728  (*consdata)->nlrow = NULL;
729  (*consdata)->weightsum = 0;
730  (*consdata)->onesweightsum = 0;
731  (*consdata)->ncliques = 0;
732  (*consdata)->nnegcliques = 0;
733  (*consdata)->presolvedtiming = 0;
734  (*consdata)->sorted = FALSE;
735  (*consdata)->cliquepartitioned = FALSE;
736  (*consdata)->negcliquepartitioned = FALSE;
737  (*consdata)->ncliqueslastpart = -1;
738  (*consdata)->ncliqueslastnegpart = -1;
739  (*consdata)->merged = FALSE;
740  (*consdata)->cliquesadded = FALSE;
741  (*consdata)->varsdeleted = FALSE;
742  (*consdata)->existmultaggr = FALSE;
743 
744  /* get transformed variables, if we are in the transformed problem */
745  if( SCIPisTransformed(scip) )
746  {
747  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
748 
749  for( v = 0; v < (*consdata)->nvars; v++ )
750  {
751  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
752  assert(var != NULL);
753  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
754  }
755 
756  /* allocate memory for additional data structures */
757  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
758  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
759  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
760  }
761 
762  /* calculate sum of weights and capture variables */
763  for( v = 0; v < (*consdata)->nvars; ++v )
764  {
765  /* calculate sum of weights */
766  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
767 
768  /* capture variables */
769  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
770  }
771  return SCIP_OKAY;
772 }
773 
774 /** frees knapsack constraint data */
775 static
777  SCIP* scip, /**< SCIP data structure */
778  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
779  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
780  )
781 {
782  assert(consdata != NULL);
783  assert(*consdata != NULL);
785  if( (*consdata)->row != NULL )
786  {
787  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
788  }
789  if( (*consdata)->nlrow != NULL )
790  {
791  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
792  }
793  if( (*consdata)->eventdata != NULL )
794  {
795  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
796  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
797  }
798  if( (*consdata)->negcliquepartition != NULL )
799  {
800  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
801  }
802  if( (*consdata)->cliquepartition != NULL )
803  {
804  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
805  }
806  if( (*consdata)->vars != NULL )
807  {
808  int v;
809 
810  /* release variables */
811  for( v = 0; v < (*consdata)->nvars; v++ )
812  {
813  assert((*consdata)->vars[v] != NULL);
814  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
815  }
816 
817  assert( (*consdata)->weights != NULL );
818  assert( (*consdata)->varssize > 0 );
819  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
820  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
821  }
822 
823  SCIPfreeBlockMemory(scip, consdata);
824 
825  return SCIP_OKAY;
826 }
827 
828 /** changes a single weight in knapsack constraint data */
829 static
830 void consdataChgWeight(
831  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
832  int item, /**< item number */
833  SCIP_Longint newweight /**< new weight of item */
834  )
835 {
836  SCIP_Longint oldweight;
837  SCIP_Longint weightdiff;
839  assert(consdata != NULL);
840  assert(0 <= item && item < consdata->nvars);
841 
842  oldweight = consdata->weights[item];
843  weightdiff = newweight - oldweight;
844  consdata->weights[item] = newweight;
845 
846  /* update weight sums for all and fixed variables */
847  updateWeightSums(consdata, consdata->vars[item], weightdiff);
848 
849  if( consdata->eventdata != NULL )
850  {
851  assert(consdata->eventdata[item] != NULL);
852  assert(consdata->eventdata[item]->weight == oldweight);
853  consdata->eventdata[item]->weight = newweight;
854  }
855 
856  consdata->presolvedtiming = 0;
857  consdata->sorted = FALSE;
858 
859  /* recalculate cliques extraction after a weight was increased */
860  if( oldweight < newweight )
861  {
862  consdata->cliquesadded = FALSE;
863  }
864 }
865 
866 /** creates LP row corresponding to knapsack constraint */
867 static
869  SCIP* scip, /**< SCIP data structure */
870  SCIP_CONS* cons /**< knapsack constraint */
871  )
872 {
873  SCIP_CONSDATA* consdata;
874  int i;
875 
876  consdata = SCIPconsGetData(cons);
877  assert(consdata != NULL);
878  assert(consdata->row == NULL);
879 
880  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
881  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
883 
884  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
885  for( i = 0; i < consdata->nvars; ++i )
886  {
887  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
888  }
889  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
890 
891  return SCIP_OKAY;
892 }
893 
894 /** adds linear relaxation of knapsack constraint to the LP */
895 static
897  SCIP* scip, /**< SCIP data structure */
898  SCIP_CONS* cons, /**< knapsack constraint */
899  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
900  )
901 {
902  SCIP_CONSDATA* consdata;
903 
904  assert( cutoff != NULL );
905  *cutoff = FALSE;
906 
907  consdata = SCIPconsGetData(cons);
908  assert(consdata != NULL);
909 
910  if( consdata->row == NULL )
911  {
912  SCIP_CALL( createRelaxation(scip, cons) );
913  }
914  assert(consdata->row != NULL);
915 
916  /* insert LP row as cut */
917  if( !SCIProwIsInLP(consdata->row) )
918  {
919  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
920  SCIPconsGetName(cons), consdata->capacity);
921  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
922  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
923  }
924 
925  return SCIP_OKAY;
926 }
927 
928 /** adds knapsack constraint as row to the NLP, if not added yet */
929 static
931  SCIP* scip, /**< SCIP data structure */
932  SCIP_CONS* cons /**< knapsack constraint */
933  )
934 {
935  SCIP_CONSDATA* consdata;
936 
937  assert(SCIPisNLPConstructed(scip));
939  /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
940  if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
941  return SCIP_OKAY;
942 
943  consdata = SCIPconsGetData(cons);
944  assert(consdata != NULL);
945 
946  if( consdata->nlrow == NULL )
947  {
948  SCIP_Real* coefs;
949  int i;
950 
951  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
952  for( i = 0; i < consdata->nvars; ++i )
953  coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
954 
955  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
956  consdata->nvars, consdata->vars, coefs, NULL,
957  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
958 
959  assert(consdata->nlrow != NULL);
960 
961  SCIPfreeBufferArray(scip, &coefs);
962  }
963 
964  if( !SCIPnlrowIsInNLP(consdata->nlrow) )
965  {
966  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
967  }
968 
969  return SCIP_OKAY;
970 }
971 
972 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
973 static
975  SCIP* scip, /**< SCIP data structure */
976  SCIP_CONS* cons, /**< constraint to check */
977  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
978  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
979  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
980  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
981  )
982 {
983  SCIP_CONSDATA* consdata;
984 
985  assert(violated != NULL);
986 
987  consdata = SCIPconsGetData(cons);
988  assert(consdata != NULL);
989 
990  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
991  SCIPconsGetName(cons), (void*)sol, checklprows);
992 
993  *violated = FALSE;
994 
995  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
996  {
997  SCIP_Real sum;
998  SCIP_Longint integralsum;
999  SCIP_Bool ishuge;
1000  SCIP_Real absviol;
1001  SCIP_Real relviol;
1002  int v;
1003 
1004  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1005  * enforcement
1006  */
1007  if( sol == NULL )
1008  {
1009  SCIP_CALL( SCIPincConsAge(scip, cons) );
1010  }
1011 
1012  sum = 0.0;
1013  integralsum = 0;
1014  /* we perform a more exact comparison if the capacity does not exceed the huge value */
1015  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
1016  {
1017  ishuge = TRUE;
1018 
1019  /* sum over all weight times the corresponding solution value */
1020  for( v = consdata->nvars - 1; v >= 0; --v )
1021  {
1022  assert(SCIPvarIsBinary(consdata->vars[v]));
1023  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1024  }
1025  }
1026  else
1027  {
1028  ishuge = FALSE;
1029 
1030  /* sum over all weight for which the variable has a solution value of 1 in feastol */
1031  for( v = consdata->nvars - 1; v >= 0; --v )
1032  {
1033  assert(SCIPvarIsBinary(consdata->vars[v]));
1034 
1035  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
1036  integralsum += consdata->weights[v];
1037  }
1038  }
1039 
1040  /* calculate constraint violation and update it in solution */
1041  absviol = ishuge ? sum : (SCIP_Real)integralsum;
1042  absviol -= consdata->capacity;
1043  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
1044  if( sol != NULL )
1045  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1046 
1047  if( SCIPisFeasPositive(scip, absviol) )
1048  {
1049  *violated = TRUE;
1050 
1051  /* only reset constraint age if we are in enforcement */
1052  if( sol == NULL )
1053  {
1054  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1055  }
1056 
1057  if( printreason )
1058  {
1059  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1060 
1061  SCIPinfoMessage(scip, NULL, ";\n");
1062  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1063  }
1064  }
1065  }
1066 
1067  return SCIP_OKAY;
1068 }
1069 
1070 /* IDX computes the integer index for the optimal solution array */
1071 #define IDX(j,d) ((j)*(intcap)+(d))
1072 
1073 /** solves knapsack problem in maximization form exactly using dynamic programming;
1074  * if needed, one can provide arrays to store all selected items and all not selected items
1075  *
1076  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1077  *
1078  * @note the algorithm will first compute a greedy solution and terminate
1079  * if the greedy solution is proven to be optimal.
1080  * The dynamic programming algorithm runs with a time and space complexity
1081  * of O(nitems * capacity).
1082  *
1083  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1084  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1085  * to be checked whether they are faster and whether they can reconstruct the solution.
1086  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1087  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1088  * This could be implemented, however, it would be technically a bit cumbersome,
1089  * since one needs the greedy solution and the LP-value for this.
1090  * This is currently only available after the redundant items have already been sorted out.
1091  */
1093  SCIP* scip, /**< SCIP data structure */
1094  int nitems, /**< number of available items */
1095  SCIP_Longint* weights, /**< item weights */
1096  SCIP_Real* profits, /**< item profits */
1097  SCIP_Longint capacity, /**< capacity of knapsack */
1098  int* items, /**< item numbers */
1099  int* solitems, /**< array to store items in solution, or NULL */
1100  int* nonsolitems, /**< array to store items not in solution, or NULL */
1101  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1102  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1103  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1104  SCIP_Bool* success /**< pointer to store if an error occured during solving
1105  * (normally a memory problem) */
1106  )
1107 {
1108  SCIP_RETCODE retcode;
1109  SCIP_Real* tempsort;
1110  SCIP_Real* optvalues;
1111  int intcap;
1112  int d;
1113  int j;
1114  int greedymedianpos;
1115  SCIP_Longint weightsum;
1116  int* myitems;
1117  SCIP_Longint* myweights;
1118  SCIP_Real* realweights;
1119  int* allcurrminweight;
1120  SCIP_Real* myprofits;
1121  int nmyitems;
1122  SCIP_Longint gcd;
1123  SCIP_Longint minweight;
1124  SCIP_Longint maxweight;
1125  int currminweight;
1126  SCIP_Longint greedysolweight;
1127  SCIP_Real greedysolvalue;
1128  SCIP_Real greedyupperbound;
1129  SCIP_Bool eqweights;
1130  SCIP_Bool intprofits;
1131 
1132  assert(weights != NULL);
1133  assert(profits != NULL);
1134  assert(capacity >= 0);
1135  assert(items != NULL);
1136  assert(nitems >= 0);
1137  assert(success != NULL);
1138 
1139  *success = TRUE;
1140 
1141 #ifndef NDEBUG
1142  for( j = nitems - 1; j >= 0; --j )
1143  assert(weights[j] >= 0);
1144 #endif
1145 
1146  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1147 
1148  /* initializing solution value */
1149  if( solval != NULL )
1150  *solval = 0.0;
1151 
1152  /* init solution information */
1153  if( solitems != NULL )
1154  {
1155  assert(items != NULL);
1156  assert(nsolitems != NULL);
1157  assert(nonsolitems != NULL);
1158  assert(nnonsolitems != NULL);
1159 
1160  *nnonsolitems = 0;
1161  *nsolitems = 0;
1162  }
1163 
1164  /* allocate temporary memory */
1165  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1166  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1167  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1168  nmyitems = 0;
1169  weightsum = 0;
1170  minweight = SCIP_LONGINT_MAX;
1171  maxweight = 0;
1172 
1173  /* remove unnecessary items */
1174  for( j = 0; j < nitems; ++j )
1175  {
1176  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1177 
1178  /* item does not fit */
1179  if( weights[j] > capacity )
1180  {
1181  if( solitems != NULL )
1182  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1183  }
1184  /* item is not profitable */
1185  else if( profits[j] <= 0.0 )
1186  {
1187  if( solitems != NULL )
1188  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1189  }
1190  /* item always fits */
1191  else if( weights[j] == 0 )
1192  {
1193  if( solitems != NULL )
1194  solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1195 
1196  if( solval != NULL )
1197  *solval += profits[j];
1198  }
1199  /* all important items */
1200  else
1201  {
1202  myweights[nmyitems] = weights[j];
1203  myprofits[nmyitems] = profits[j];
1204  myitems[nmyitems] = items[j];
1205 
1206  /* remember smallest item */
1207  if( myweights[nmyitems] < minweight )
1208  minweight = myweights[nmyitems];
1209 
1210  /* remember bigest item */
1211  if( myweights[nmyitems] > maxweight )
1212  maxweight = myweights[nmyitems];
1213 
1214  weightsum += myweights[nmyitems];
1215  ++nmyitems;
1216  }
1217  }
1218 
1219  intprofits = TRUE;
1220  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1221  for( j = 0; j < nmyitems && intprofits; ++j )
1222  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1223 
1224  /* if no item is left then goto end */
1225  if( nmyitems == 0 )
1226  {
1227  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1228 
1229  goto TERMINATE;
1230  }
1231 
1232  /* if all items fit, we also do not need to do the expensive stuff later on */
1233  if( weightsum > 0 && weightsum <= capacity )
1234  {
1235  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1236 
1237  for( j = nmyitems - 1; j >= 0; --j )
1238  {
1239  if( solitems != NULL )
1240  solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1241 
1242  if( solval != NULL )
1243  *solval += myprofits[j];
1244  }
1245 
1246  goto TERMINATE;
1247  }
1248 
1249  assert(0 < minweight && minweight <= capacity );
1250  assert(0 < maxweight && maxweight <= capacity);
1251 
1252  /* make weights relatively prime */
1253  eqweights = TRUE;
1254  if( maxweight > 1 )
1255  {
1256  /* determine greatest common divisor */
1257  gcd = myweights[nmyitems - 1];
1258  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1259  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1260 
1261  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1262 
1263  /* divide by greatest common divisor */
1264  if( gcd > 1 )
1265  {
1266  for( j = nmyitems - 1; j >= 0; --j )
1267  {
1268  myweights[j] /= gcd;
1269  eqweights = eqweights && (myweights[j] == 1);
1270  }
1271  capacity /= gcd;
1272  minweight /= gcd;
1273  }
1274  else
1275  eqweights = FALSE;
1276  }
1277  assert(minweight <= capacity);
1278 
1279  /* if only one item fits, then take the best */
1280  if( minweight > capacity / 2 )
1281  {
1282  int p;
1283 
1284  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1285 
1286  p = nmyitems - 1;
1287 
1288  /* find best item */
1289  for( j = nmyitems - 2; j >= 0; --j )
1290  {
1291  if( myprofits[j] > myprofits[p] )
1292  p = j;
1293  }
1294 
1295  /* update solution information */
1296  if( solitems != NULL )
1297  {
1298  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1299 
1300  solitems[(*nsolitems)++] = myitems[p];
1301  for( j = nmyitems - 1; j >= 0; --j )
1302  {
1303  if( j != p )
1304  nonsolitems[(*nnonsolitems)++] = myitems[j];
1305  }
1306  }
1307  /* update solution value */
1308  if( solval != NULL )
1309  *solval += myprofits[p];
1310 
1311  goto TERMINATE;
1312  }
1313 
1314  /* if all items have the same weight, then take the best */
1315  if( eqweights )
1316  {
1317  SCIP_Real addval = 0.0;
1318 
1319  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1320 
1321  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1322 
1323  /* update solution information */
1324  if( solitems != NULL || solval != NULL )
1325  {
1326  SCIP_Longint i;
1327 
1328  /* if all items would fit we had handled this case before */
1329  assert((SCIP_Longint) nmyitems > capacity);
1330  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1331 
1332  /* take the first best items into the solution */
1333  for( i = capacity - 1; i >= 0; --i )
1334  {
1335  if( solitems != NULL )
1336  solitems[(*nsolitems)++] = myitems[i];
1337  addval += myprofits[i];
1338  }
1339 
1340  if( solitems != NULL )
1341  {
1342  /* the rest are not in the solution */
1343  for( i = nmyitems - 1; i >= capacity; --i )
1344  nonsolitems[(*nnonsolitems)++] = myitems[i];
1345  }
1346  }
1347  /* update solution value */
1348  if( solval != NULL )
1349  {
1350  assert(addval > 0.0);
1351  *solval += addval;
1352  }
1353 
1354  goto TERMINATE;
1355  }
1356 
1357  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1358 
1359  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1360  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1361  */
1362  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1363  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1364 
1365  for( j = 0; j < nmyitems; ++j )
1366  {
1367  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1368  realweights[j] = (SCIP_Real)myweights[j];
1369  }
1370 
1371  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1372  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1373 
1374  SCIPfreeBufferArray(scip, &realweights);
1375  SCIPfreeBufferArray(scip, &tempsort);
1376 
1377  /* initialize values for greedy solution information */
1378  greedysolweight = 0;
1379  greedysolvalue = 0.0;
1380 
1381  /* determine greedy solution */
1382  for( j = 0; j < greedymedianpos; ++j )
1383  {
1384  assert(myweights[j] <= capacity);
1385 
1386  /* update greedy solution weight and value */
1387  greedysolweight += myweights[j];
1388  greedysolvalue += myprofits[j];
1389  }
1390 
1391  assert(0 < greedysolweight && greedysolweight <= capacity);
1392  assert(greedysolvalue > 0.0);
1393 
1394  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1395  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1396  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1397  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1398  if( intprofits )
1399  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1400  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1401  {
1402  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1403 
1404  /* update solution information */
1405  if( solitems != NULL )
1406  {
1407  int l;
1408 
1409  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1410 
1411  /* collect items */
1412  for( l = 0; l < j; ++l )
1413  solitems[(*nsolitems)++] = myitems[l];
1414  for ( ; l < nmyitems; ++l )
1415  nonsolitems[(*nnonsolitems)++] = myitems[l];
1416  }
1417  /* update solution value */
1418  if( solval != NULL )
1419  {
1420  assert(greedysolvalue > 0.0);
1421  *solval += greedysolvalue;
1422  }
1423 
1424  goto TERMINATE;
1425  }
1426 
1427  /* in the following table we do not need the first minweight columns */
1428  capacity -= (minweight - 1);
1429 
1430  /* we can only handle integers */
1431  if( capacity >= INT_MAX )
1432  {
1433  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1434 
1435  *success = FALSE;
1436  goto TERMINATE;
1437  }
1438  assert(capacity < INT_MAX);
1439 
1440  intcap = (int)capacity;
1441  assert(intcap >= 0);
1442  assert(nmyitems > 0);
1443  assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1444 
1445  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1446  * computing the size for the allocation
1447  */
1448  if( intcap < 0 || (intcap > 0 && (((size_t)nmyitems) > (SIZE_MAX / (size_t)intcap / sizeof(*optvalues)) || ((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues) > ((size_t)INT_MAX) )) ) /*lint !e571*/
1449  {
1450  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1451 
1452  *success = FALSE;
1453  goto TERMINATE;
1454  }
1455 
1456  /* allocate temporary memory and check for memory exceedance */
1457  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1458  if( retcode == SCIP_NOMEMORY )
1459  {
1460  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1461 
1462  *success = FALSE;
1463  goto TERMINATE;
1464  }
1465  else
1466  {
1467  SCIP_CALL( retcode );
1468  }
1469 
1470  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1471 
1472  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1473  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1474  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1475  * 'nmyitem' values
1476  */
1477  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1478  assert(myweights[0] - minweight < INT_MAX);
1479  currminweight = (int) (myweights[0] - minweight);
1480  allcurrminweight[0] = currminweight;
1481 
1482  /* fills first row of dynamic programming table with optimal values */
1483  for( d = currminweight; d < intcap; ++d )
1484  optvalues[d] = myprofits[0];
1485 
1486  /* fills dynamic programming table with optimal values */
1487  for( j = 1; j < nmyitems; ++j )
1488  {
1489  int intweight;
1490 
1491  /* compute important part of weight, which will be represented in the table */
1492  intweight = (int)(myweights[j] - minweight);
1493  assert(0 <= intweight && intweight < intcap);
1494 
1495  /* copy all nonzeros from row above */
1496  for( d = currminweight; d < intweight && d < intcap; ++d )
1497  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1498 
1499  /* update corresponding row */
1500  for( d = intweight; d < intcap; ++d )
1501  {
1502  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1503  if( d < currminweight )
1504  optvalues[IDX(j,d)] = myprofits[j];
1505  else
1506  {
1507  SCIP_Real sumprofit;
1508 
1509  if( d - myweights[j] < currminweight )
1510  sumprofit = myprofits[j];
1511  else
1512  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1513 
1514  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1515  }
1516  }
1517 
1518  /* update currminweight */
1519  if( intweight < currminweight )
1520  currminweight = intweight;
1521 
1522  allcurrminweight[j] = currminweight;
1523  }
1524 
1525  /* update optimal solution by following the table */
1526  if( solitems != NULL )
1527  {
1528  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1529  d = intcap - 1;
1530 
1531  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1532 
1533  /* insert all items in (non-) solution vector */
1534  for( j = nmyitems - 1; j > 0; --j )
1535  {
1536  /* if the following condition holds this means all remaining items does not fit anymore */
1537  if( d < allcurrminweight[j] )
1538  {
1539  /* we cannot have exceeded our capacity */
1540  assert((SCIP_Longint) d >= -minweight);
1541  break;
1542  }
1543 
1544  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1545  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1546  {
1547  solitems[(*nsolitems)++] = myitems[j];
1548 
1549  /* check that we do not have an underflow */
1550  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1551  d = (int)(d - myweights[j]);
1552  }
1553  /* collect non-solution items */
1554  else
1555  nonsolitems[(*nnonsolitems)++] = myitems[j];
1556  }
1557 
1558  /* insert remaining items */
1559  if( d >= allcurrminweight[j] )
1560  {
1561  assert(j == 0);
1562  solitems[(*nsolitems)++] = myitems[j];
1563  }
1564  else
1565  {
1566  assert(j >= 0);
1567  assert(d < allcurrminweight[j]);
1568 
1569  for( ; j >= 0; --j )
1570  nonsolitems[(*nnonsolitems)++] = myitems[j];
1571  }
1572 
1573  assert(*nsolitems + *nnonsolitems == nitems);
1574  }
1575 
1576  /* update solution value */
1577  if( solval != NULL )
1578  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1579  SCIPfreeBufferArray(scip, &allcurrminweight);
1580 
1581  /* free all temporary memory */
1582  SCIPfreeBufferArray(scip, &optvalues);
1583 
1584  TERMINATE:
1585  SCIPfreeBufferArray(scip, &myitems);
1586  SCIPfreeBufferArray(scip, &myprofits);
1587  SCIPfreeBufferArray(scip, &myweights);
1588 
1589  return SCIP_OKAY;
1590 }
1591 
1592 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1593  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1594  * selected items
1595  */
1597  SCIP* scip, /**< SCIP data structure */
1598  int nitems, /**< number of available items */
1599  SCIP_Longint* weights, /**< item weights */
1600  SCIP_Real* profits, /**< item profits */
1601  SCIP_Longint capacity, /**< capacity of knapsack */
1602  int* items, /**< item numbers */
1603  int* solitems, /**< array to store items in solution, or NULL */
1604  int* nonsolitems, /**< array to store items not in solution, or NULL */
1605  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1606  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1607  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1608  )
1609 {
1610  SCIP_Real* tempsort;
1611  SCIP_Longint solitemsweight;
1612  SCIP_Real* realweights;
1613  int j;
1614  int criticalindex;
1615 
1616  assert(weights != NULL);
1617  assert(profits != NULL);
1618  assert(capacity >= 0);
1619  assert(items != NULL);
1620  assert(nitems >= 0);
1621 
1622  if( solitems != NULL )
1623  {
1624  *nsolitems = 0;
1625  *nnonsolitems = 0;
1626  }
1627  if( solval != NULL )
1628  *solval = 0.0;
1629 
1630  /* initialize data for median search */
1631  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1632  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1633  for( j = nitems - 1; j >= 0; --j )
1634  {
1635  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1636  realweights[j] = (SCIP_Real)weights[j];
1637  }
1638 
1639  /* partially sort indices such that all elements that are larger than the break item appear first */
1640  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1641 
1642  /* selects items as long as they fit into the knapsack */
1643  solitemsweight = 0;
1644  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1645  {
1646  if( solitems != NULL )
1647  solitems[(*nsolitems)++] = items[j];
1648 
1649  if( solval != NULL )
1650  (*solval) += profits[j];
1651  solitemsweight += weights[j];
1652  }
1653  if ( solitems != NULL )
1654  {
1655  for( ; j < nitems; j++ )
1656  nonsolitems[(*nnonsolitems)++] = items[j];
1657  }
1658 
1659  SCIPfreeBufferArray(scip, &realweights);
1660  SCIPfreeBufferArray(scip, &tempsort);
1661 
1662  return SCIP_OKAY;
1663 }
1664 
1665 #ifdef SCIP_DEBUG
1666 /** prints all nontrivial GUB constraints and their LP solution values */
1667 static
1668 void GUBsetPrint(
1669  SCIP* scip, /**< SCIP data structure */
1670  SCIP_GUBSET* gubset, /**< GUB set data structure */
1671  SCIP_VAR** vars, /**< variables in knapsack constraint */
1672  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1673  )
1674 {
1675  int nnontrivialgubconss;
1676  int c;
1677 
1678  nnontrivialgubconss = 0;
1679 
1680  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1681 
1682  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1683  for( c = 0; c < gubset->ngubconss; c++ )
1684  {
1685  SCIP_Real gubsolval;
1686 
1687  assert(gubset->gubconss[c]->ngubvars >= 0);
1688 
1689  /* nontrivial GUB */
1690  if( gubset->gubconss[c]->ngubvars > 1 )
1691  {
1692  int v;
1693 
1694  gubsolval = 0.0;
1695  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1696 
1697  /* print GUB var */
1698  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1699  {
1700  int currentvar;
1701 
1702  currentvar = gubset->gubconss[c]->gubvars[v];
1703  if( solvals != NULL )
1704  {
1705  gubsolval += solvals[currentvar];
1706  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1707  }
1708  else
1709  {
1710  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1711  }
1712  }
1713 
1714  /* check whether LP solution satisfies the GUB constraint */
1715  if( solvals != NULL )
1716  {
1717  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1718  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1719  }
1720  else
1721  {
1722  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1723  }
1724  nnontrivialgubconss++;
1725  }
1726  }
1727 
1728  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1729 }
1730 #endif
1731 
1732 /** creates an empty GUB constraint */
1733 static
1735  SCIP* scip, /**< SCIP data structure */
1736  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1737  )
1738 {
1739  assert(scip != NULL);
1740  assert(gubcons != NULL);
1741 
1742  /* allocate memory for GUB constraint data structures */
1743  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1744  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1745  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1746  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1747 
1748  (*gubcons)->ngubvars = 0;
1749 
1750  return SCIP_OKAY;
1751 }
1752 
1753 /** frees GUB constraint */
1754 static
1755 void GUBconsFree(
1756  SCIP* scip, /**< SCIP data structure */
1757  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1758  )
1759 {
1760  assert(scip != NULL);
1761  assert(gubcons != NULL);
1762  assert((*gubcons)->gubvars != NULL);
1763  assert((*gubcons)->gubvarsstatus != NULL);
1764 
1765  /* free allocated memory */
1766  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1767  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1768  SCIPfreeBuffer(scip, gubcons);
1769 }
1770 
1771 /** adds variable to given GUB constraint */
1772 static
1774  SCIP* scip, /**< SCIP data structure */
1775  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1776  int var /**< index of given variable in knapsack constraint */
1777  )
1778 {
1779  assert(scip != NULL);
1780  assert(gubcons != NULL);
1781  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1782  assert(gubcons->gubvars != NULL);
1783  assert(gubcons->gubvarsstatus != NULL);
1784  assert(var >= 0);
1785 
1786  /* add variable to GUB constraint */
1787  gubcons->gubvars[gubcons->ngubvars] = var;
1788  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1789  gubcons->ngubvars++;
1790 
1791  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1792  if( gubcons->ngubvars == gubcons->gubvarssize )
1793  {
1794  int newlen;
1795 
1796  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1797  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1798  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1799 
1800  gubcons->gubvarssize = newlen;
1801  }
1802 
1803  return SCIP_OKAY;
1804 }
1805 
1806 /** deletes variable from its current GUB constraint */
1807 static
1809  SCIP* scip, /**< SCIP data structure */
1810  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1811  int var, /**< index of given variable in knapsack constraint */
1812  int gubvarsidx /**< index of the variable in its current GUB constraint */
1813  )
1814 {
1815  assert(scip != NULL);
1816  assert(gubcons != NULL);
1817  assert(var >= 0);
1818  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1819  assert(gubcons->ngubvars >= gubvarsidx+1);
1820  assert(gubcons->gubvars[gubvarsidx] == var);
1821 
1822  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1823  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1824  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1825  gubcons->ngubvars--;
1826 
1827  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1828  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1829  {
1830  int newlen;
1831 
1832  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1833 
1834  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1835  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1836 
1837  gubcons->gubvarssize = newlen;
1838  }
1839 
1840  return SCIP_OKAY;
1841 }
1842 
1843 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1844 static
1846  SCIP* scip, /**< SCIP data structure */
1847  SCIP_GUBSET* gubset, /**< GUB set data structure */
1848  SCIP_VAR** vars, /**< variables in knapsack constraint */
1849  int var, /**< index of given variable in knapsack constraint */
1850  int oldgubcons, /**< index of old GUB constraint of given variable */
1851  int newgubcons /**< index of new GUB constraint of given variable */
1852  )
1854  int oldgubvaridx;
1855  int replacevar;
1856  int j;
1857 
1858  assert(scip != NULL);
1859  assert(gubset != NULL);
1860  assert(var >= 0);
1861  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1862  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1863  assert(oldgubcons != newgubcons);
1864  assert(gubset->gubconssidx[var] == oldgubcons);
1865  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1866  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1867 
1868  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1869 
1870  oldgubvaridx = gubset->gubvarsidx[var];
1871 
1872  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1873  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1874 
1875  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1876  * replacement variable is given by old position of the deleted variable
1877  */
1878  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1879  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1880  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1881 
1882  /* add variable to the end of new GUB constraint */
1883  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1884  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1885 
1886  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1887  gubset->gubconssidx[var] = newgubcons;
1888  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1889 
1890  /* delete old GUB constraint if it became empty */
1891  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1892  {
1893  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1894 #ifdef SCIP_DEBUG
1895  GUBsetPrint(scip, gubset, vars, NULL);
1896 #endif
1897 
1898  /* free old GUB constraint */
1899  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1900 
1901  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1902  if( oldgubcons != gubset->ngubconss-1 )
1903  {
1904  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1905  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1906 
1907  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1908  * replacement GUB is given by old position of the deleted GUB
1909  */
1910  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1911  {
1912  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1913  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1914  }
1915  }
1916 
1917  /* update number of GUB constraints */
1918  gubset->ngubconss--;
1919 
1920  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1921  * (because it was at the end of the GUB constraint array)
1922  */
1923  assert(gubset->gubconssidx[var] == newgubcons
1924  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1925  }
1926 #ifndef NDEBUG
1927  else
1928  assert(gubset->gubconssidx[var] == newgubcons);
1929 #endif
1930 
1931  return SCIP_OKAY;
1932 }
1933 
1934 /** swaps two variables in the same GUB constraint */
1935 static
1936 void GUBsetSwapVars(
1937  SCIP* scip, /**< SCIP data structure */
1938  SCIP_GUBSET* gubset, /**< GUB set data structure */
1939  int var1, /**< first variable to be swapped */
1940  int var2 /**< second variable to be swapped */
1941  )
1942 {
1943  int gubcons;
1944  int var1idx;
1945  GUBVARSTATUS var1status;
1946  int var2idx;
1947  GUBVARSTATUS var2status;
1948 
1949  assert(scip != NULL);
1950  assert(gubset != NULL);
1951 
1952  gubcons = gubset->gubconssidx[var1];
1953  assert(gubcons == gubset->gubconssidx[var2]);
1954 
1955  /* nothing to be done if both variables are the same */
1956  if( var1 == var2 )
1957  return;
1958 
1959  /* swap index and status of variables in GUB constraint */
1960  var1idx = gubset->gubvarsidx[var1];
1961  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1962  var2idx = gubset->gubvarsidx[var2];
1963  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1964 
1965  gubset->gubvarsidx[var1] = var2idx;
1966  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1967  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1968 
1969  gubset->gubvarsidx[var2] = var1idx;
1970  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1971  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1972 }
1973 
1974 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1975 static
1977  SCIP* scip, /**< SCIP data structure */
1978  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1979  int nvars, /**< number of variables in the knapsack constraint */
1980  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1981  SCIP_Longint capacity /**< capacity of knapsack */
1982  )
1983 {
1984  int i;
1985 
1986  assert(scip != NULL);
1987  assert(gubset != NULL);
1988  assert(nvars > 0);
1989  assert(weights != NULL);
1990  assert(capacity >= 0);
1991 
1992  /* allocate memory for GUB set data structures */
1993  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1994  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1995  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1996  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1997  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1998  (*gubset)->ngubconss = nvars;
1999  (*gubset)->nvars = nvars;
2000 
2001  /* initialize the set of GUB constraints */
2002  for( i = 0; i < nvars; i++ )
2003  {
2004  /* assign each variable to a new (trivial) GUB constraint */
2005  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2006  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2007 
2008  /* set status of GUB constraint to initial */
2009  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2010 
2011  (*gubset)->gubconssidx[i] = i;
2012  (*gubset)->gubvarsidx[i] = 0;
2013  assert((*gubset)->gubconss[i]->ngubvars == 1);
2014 
2015  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2016  if( weights[i] > capacity )
2017  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2018  }
2019 
2020  return SCIP_OKAY;
2021 }
2022 
2023 /** frees GUB set data structure */
2024 static
2025 void GUBsetFree(
2026  SCIP* scip, /**< SCIP data structure */
2027  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2028  )
2029 {
2030  int i;
2031 
2032  assert(scip != NULL);
2033  assert(gubset != NULL);
2034  assert((*gubset)->gubconss != NULL);
2035  assert((*gubset)->gubconsstatus != NULL);
2036  assert((*gubset)->gubconssidx != NULL);
2037  assert((*gubset)->gubvarsidx != NULL);
2038 
2039  /* free all GUB constraints */
2040  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2041  {
2042  assert((*gubset)->gubconss[i] != NULL);
2043  GUBconsFree(scip, &(*gubset)->gubconss[i]);
2044  }
2045 
2046  /* free allocated memory */
2047  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2048  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2049  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2050  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2051  SCIPfreeBuffer(scip, gubset);
2052 }
2053 
2054 #ifndef NDEBUG
2055 /** checks whether GUB set data structure is consistent */
2056 static
2058  SCIP* scip, /**< SCIP data structure */
2059  SCIP_GUBSET* gubset, /**< GUB set data structure */
2060  SCIP_VAR** vars /**< variables in the knapsack constraint */
2061  )
2062 {
2063  int i;
2064  int gubconsidx;
2065  int gubvaridx;
2066  SCIP_VAR* var1;
2067  SCIP_VAR* var2;
2068  SCIP_Bool var1negated;
2069  SCIP_Bool var2negated;
2070 
2071  assert(scip != NULL);
2072  assert(gubset != NULL);
2073 
2074  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2075 
2076  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2077  for( i = 0; i < gubset->nvars; i++ )
2078  {
2079  gubconsidx = gubset->gubconssidx[i];
2080  gubvaridx = gubset->gubvarsidx[i];
2081 
2082  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2083  {
2084  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2085  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2086  }
2087  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2088  }
2089 
2090  /* checks for each GUB whether all pairs of its variables have a common clique */
2091  for( i = 0; i < gubset->ngubconss; i++ )
2092  {
2093  int j;
2094 
2095  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2096  {
2097  int k;
2098 
2099  /* get corresponding active problem variable */
2100  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2101  var1negated = FALSE;
2102  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2103 
2104  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2105  {
2106  /* get corresponding active problem variable */
2107  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2108  var2negated = FALSE;
2109  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2110 
2111  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2112  {
2113  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2114  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2115  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2116  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2117  SCIPvarGetName(var1), k,
2118  SCIPvarGetName(var2));
2119  }
2120 
2121  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2122  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2123  }
2124  }
2125  }
2126  SCIPdebugMsg(scip, " --> successful\n");
2127 
2128  return SCIP_OKAY;
2129 }
2130 #endif
2131 
2132 /** calculates a partition of the given set of binary variables into cliques;
2133  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2134  * were assigned to the same clique;
2135  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2136  * the preceding variables was assigned to clique i-1;
2137  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2138  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2139  */
2140 
2141 static
2143  SCIP*const scip, /**< SCIP data structure */
2144  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2145  int const nvars, /**< number of variables in the clique */
2146  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2147  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2148  SCIP_Real* solvals /**< solution values of all given binary variables */
2149  )
2151  SCIP_VAR** tmpvars;
2152  SCIP_VAR** cliquevars;
2153  SCIP_Bool* cliquevalues;
2154  SCIP_Bool* tmpvalues;
2155  int* varseq;
2156  int* sortkeys;
2157  int ncliquevars;
2158  int maxncliquevarscomp;
2159  int nignorevars;
2160  int nvarsused;
2161  int i;
2162 
2163  assert(scip != NULL);
2164  assert(nvars == 0 || vars != NULL);
2165  assert(nvars == 0 || cliquepartition != NULL);
2166  assert(ncliques != NULL);
2167 
2168  if( nvars == 0 )
2169  {
2170  *ncliques = 0;
2171  return SCIP_OKAY;
2172  }
2173 
2174  /* allocate temporary memory for storing the variables of the current clique */
2175  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2176  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2177  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2178  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2179  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2180  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2181 
2182  /* initialize the cliquepartition array with -1 */
2183  /* initialize the tmpvalues array */
2184  for( i = nvars - 1; i >= 0; --i )
2185  {
2186  tmpvalues[i] = TRUE;
2187  cliquepartition[i] = -1;
2188  }
2189 
2190  /* get corresponding active problem variables */
2191  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2192 
2193  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2194  * by nondecreasing number of cliques the variables are in
2195  */
2196  nignorevars = 0;
2197  nvarsused = 0;
2198  for( i = 0; i < nvars; i++ )
2199  {
2200  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2201  {
2202  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2203  varseq[nvars-1-nignorevars] = i;
2204  nignorevars++;
2205  }
2206  else
2207  {
2208  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2209  varseq[nvarsused] = i;
2210  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2211  nvarsused++;
2212  }
2213  }
2214  assert(nvarsused + nignorevars == nvars);
2215 
2216  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2217  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2218 
2219  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2220 
2221  /* calculate the clique partition */
2222  *ncliques = 0;
2223  for( i = 0; i < nvars; ++i )
2224  {
2225  if( cliquepartition[varseq[i]] == -1 )
2226  {
2227  int j;
2228 
2229  /* variable starts a new clique */
2230  cliquepartition[varseq[i]] = *ncliques;
2231  cliquevars[0] = tmpvars[varseq[i]];
2232  cliquevalues[0] = tmpvalues[varseq[i]];
2233  ncliquevars = 1;
2234 
2235  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2236  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2237  */
2238  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2239  {
2240  /* greedily fill up the clique */
2241  for( j = i + 1; j < nvarsused; ++j )
2242  {
2243  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2244  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2245  {
2246  int k;
2247 
2248  /* check if every variable in the actual clique is in clique with the new variable */
2249  for( k = ncliquevars - 1; k >= 0; --k )
2250  {
2251  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2252  cliquevalues[k], TRUE) )
2253  break;
2254  }
2255 
2256  if( k == -1 )
2257  {
2258  /* put the variable into the same clique */
2259  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2260  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2261  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2262  ++ncliquevars;
2263  }
2264  }
2265  }
2266  }
2267 
2268  /* this clique is finished */
2269  ++(*ncliques);
2270  }
2271  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2272 
2273  /* break if we reached the maximal number of comparisons */
2274  if( i * nvars > maxncliquevarscomp )
2275  break;
2276  }
2277  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2278  for( ; i < nvars; ++i )
2279  {
2280  if( cliquepartition[varseq[i]] == -1 )
2281  {
2282  cliquepartition[varseq[i]] = *ncliques;
2283  ++(*ncliques);
2284  }
2285  }
2286 
2287  /* free temporary memory */
2288  SCIPfreeBufferArray(scip, &sortkeys);
2289  SCIPfreeBufferArray(scip, &varseq);
2290  SCIPfreeBufferArray(scip, &tmpvars);
2291  SCIPfreeBufferArray(scip, &tmpvalues);
2292  SCIPfreeBufferArray(scip, &cliquevalues);
2293  SCIPfreeBufferArray(scip, &cliquevars);
2294 
2295  return SCIP_OKAY;
2296 }
2297 
2298 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2299 static
2301  SCIP* scip, /**< SCIP data structure */
2302  SCIP_GUBSET* gubset, /**< GUB set data structure */
2303  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2304  SCIP_Real* solvals /**< solution values of all knapsack variables */
2305  )
2306 {
2307  int* cliquepartition;
2308  int* gubfirstvar;
2309  int ncliques;
2310  int currentgubconsidx;
2311  int newgubconsidx;
2312  int cliqueidx;
2313  int nvars;
2314  int i;
2315 
2316  assert(scip != NULL);
2317  assert(gubset != NULL);
2318  assert(vars != NULL);
2319 
2320  nvars = gubset->nvars;
2321  assert(nvars >= 0);
2322 
2323  /* allocate temporary memory for clique partition */
2324  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2325 
2326  /* compute sophisticated clique partition */
2327  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2328 
2329  /* allocate temporary memory for GUB set data structure */
2330  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2331 
2332  /* translate GUB partition into GUB set data structure */
2333  for( i = 0; i < ncliques; i++ )
2334  {
2335  /* initialize first variable for every GUB */
2336  gubfirstvar[i] = -1;
2337  }
2338  /* move every knapsack variable into GUB defined by clique partition */
2339  for( i = 0; i < nvars; i++ )
2340  {
2341  assert(cliquepartition[i] >= 0);
2342 
2343  cliqueidx = cliquepartition[i];
2344  currentgubconsidx = gubset->gubconssidx[i];
2345  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2346 
2347  /* variable is first element in GUB constraint defined by clique partition */
2348  if( gubfirstvar[cliqueidx] == -1 )
2349  {
2350  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2351  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2352  */
2353  assert(gubset->gubvarsidx[i] == 0);
2354  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2355 
2356  /* remember the first variable found for the current GUB */
2357  gubfirstvar[cliqueidx] = i;
2358  }
2359  /* variable is additional element of GUB constraint defined by clique partition */
2360  else
2361  {
2362  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2363 
2364  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2365  * first variable of this GUB constraint
2366  */
2367  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2368  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2369  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2370 
2371  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2372  }
2373  }
2374 
2375 #ifdef SCIP_DEBUG
2376  /* prints GUB set data structure */
2377  GUBsetPrint(scip, gubset, vars, solvals);
2378 #endif
2379 
2380 #ifndef NDEBUG
2381  /* checks consistency of GUB set data structure */
2382  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2383 #endif
2384 
2385  /* free temporary memory */
2386  SCIPfreeBufferArray(scip, &gubfirstvar);
2387  SCIPfreeBufferArray(scip, &cliquepartition);
2388 
2389  return SCIP_OKAY;
2390 }
2391 
2392 /** 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$
2393  * 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
2394  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2395  */
2396 static
2398  SCIP* scip, /**< SCIP data structure */
2399  SCIP_VAR** vars, /**< variables in knapsack constraint */
2400  int nvars, /**< number of variables in knapsack constraint */
2401  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2402  SCIP_Longint capacity, /**< capacity of knapsack */
2403  SCIP_Real* solvals, /**< solution values of all problem variables */
2404  int* covervars, /**< pointer to store cover variables */
2405  int* noncovervars, /**< pointer to store noncover variables */
2406  int* ncovervars, /**< pointer to store number of cover variables */
2407  int* nnoncovervars, /**< pointer to store number of noncover variables */
2408  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2409  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2410  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2411  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2412  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2413  )
2414 {
2415  SCIP_Longint* transweights;
2416  SCIP_Real* transprofits;
2417  SCIP_Longint transcapacity;
2418  SCIP_Longint fixedonesweight;
2419  SCIP_Longint itemsweight;
2420  SCIP_Bool infeasible;
2421  int* fixedones;
2422  int* fixedzeros;
2423  int* items;
2424  int nfixedones;
2425  int nfixedzeros;
2426  int nitems;
2427  int j;
2428 
2429  assert(scip != NULL);
2430  assert(vars != NULL);
2431  assert(nvars > 0);
2432  assert(weights != NULL);
2433  assert(capacity >= 0);
2434  assert(solvals != NULL);
2435  assert(covervars != NULL);
2436  assert(noncovervars != NULL);
2437  assert(ncovervars != NULL);
2438  assert(nnoncovervars != NULL);
2439  assert(coverweight != NULL);
2440  assert(found != NULL);
2441  assert(ntightened != NULL);
2442  assert(fractional != NULL);
2443 
2444  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2445 
2446  /* allocates temporary memory */
2447  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2448  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2449  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2450  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2451  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2452 
2453  *found = FALSE;
2454  *ncovervars = 0;
2455  *nnoncovervars = 0;
2456  *coverweight = 0;
2457  *fractional = TRUE;
2458 
2459  /* gets the following sets
2460  * N_1 = {j in N : x*_j = 1} (fixedones),
2461  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2462  * N\(N_0 & N_1) (items),
2463  * where x*_j is the solution value of variable x_j
2464  */
2465  nfixedones = 0;
2466  nfixedzeros = 0;
2467  nitems = 0;
2468  fixedonesweight = 0;
2469  itemsweight = 0;
2470  *ntightened = 0;
2471  for( j = 0; j < nvars; j++ )
2472  {
2473  assert(SCIPvarIsBinary(vars[j]));
2474 
2475  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2476  if( weights[j] > capacity )
2477  {
2478  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2479  assert(!infeasible);
2480  (*ntightened)++;
2481  continue;
2482  }
2483 
2484  /* variable x_j has solution value one */
2485  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2486  {
2487  fixedones[nfixedones] = j;
2488  nfixedones++;
2489  fixedonesweight += weights[j];
2490  }
2491  /* variable x_j has solution value zero */
2492  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2493  {
2494  fixedzeros[nfixedzeros] = j;
2495  nfixedzeros++;
2496  }
2497  /* variable x_j has fractional solution value */
2498  else
2499  {
2500  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2501  items[nitems] = j;
2502  nitems++;
2503  itemsweight += weights[j];
2504  }
2505  }
2506  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2507 
2508  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2509  * the separation routine
2510  */
2511  assert(nitems >= 0);
2512  if( nitems == 0 )
2513  {
2514  *fractional = FALSE;
2515  goto TERMINATE;
2516  }
2517  assert(*fractional);
2518 
2519  /* transforms the traditional separation problem (under consideration of the following fixing:
2520  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2521  *
2522  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2523  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2524  * z_j in {0,1}, j in N\(N_0 & N_1)
2525  *
2526  * to a knapsack problem in maximization form by complementing the variables
2527  *
2528  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2529  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2530  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2531  * z_j in {0,1}, j in N\(N_0 & N_1)
2532  */
2533 
2534  /* gets weight and profit of variables in transformed knapsack problem */
2535  for( j = 0; j < nitems; j++ )
2536  {
2537  transweights[j] = weights[items[j]];
2538  transprofits[j] = 1.0 - solvals[items[j]];
2539  }
2540  /* gets capacity of transformed knapsack problem */
2541  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2542 
2543  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2544  * (when variables fixed to zero are not used)
2545  */
2546  if( transcapacity < 0 )
2547  {
2548  assert(!(*found));
2549  goto TERMINATE;
2550  }
2551 
2552  if( modtransused )
2553  {
2554  /* transforms the modified separation problem (under consideration of the following fixing:
2555  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2556  *
2557  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2558  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2559  * z_j in {0,1}, j in N\(N_0 & N_1)
2560  *
2561  * to a knapsack problem in maximization form by complementing the variables
2562  *
2563  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2564  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2565  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2566  * z_j in {0,1}, j in N\(N_0 & N_1)
2567  */
2568 
2569  /* gets weight and profit of variables in modified transformed knapsack problem */
2570  for( j = 0; j < nitems; j++ )
2571  {
2572  transprofits[j] *= weights[items[j]];
2573  assert(SCIPisFeasPositive(scip, transprofits[j]));
2574  }
2575  }
2576 
2577  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2578  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2579  * let z* be the solution, then
2580  * j in C, if z*_j = 0 and
2581  * i in N\C, if z*_j = 1.
2582  */
2583  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2584  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2585  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2586 
2587  /* constructs cover C (sum_{j in C} a_j > a_0) */
2588  for( j = 0; j < *ncovervars; j++ )
2589  {
2590  (*coverweight) += weights[covervars[j]];
2591  }
2592 
2593  /* adds all variables from N_1 to C */
2594  for( j = 0; j < nfixedones; j++ )
2595  {
2596  covervars[*ncovervars] = fixedones[j];
2597  (*ncovervars)++;
2598  (*coverweight) += weights[fixedones[j]];
2599  }
2600 
2601  /* adds all variables from N_0 to N\C */
2602  for( j = 0; j < nfixedzeros; j++ )
2603  {
2604  noncovervars[*nnoncovervars] = fixedzeros[j];
2605  (*nnoncovervars)++;
2606  }
2607  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2608  assert((*coverweight) > capacity);
2609  *found = TRUE;
2610 
2611  TERMINATE:
2612  /* frees temporary memory */
2613  SCIPfreeBufferArray(scip, &items);
2614  SCIPfreeBufferArray(scip, &fixedzeros);
2615  SCIPfreeBufferArray(scip, &fixedones);
2616  SCIPfreeBufferArray(scip, &transprofits);
2617  SCIPfreeBufferArray(scip, &transweights);
2618 
2619  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2620 
2621  return SCIP_OKAY;
2622 }
2623 
2624 #ifndef NDEBUG
2625 /** checks if minweightidx is set correctly
2626  */
2627 static
2629  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2630  SCIP_Longint capacity, /**< capacity of knapsack */
2631  int* covervars, /**< pointer to store cover variables */
2632  int ncovervars, /**< pointer to store number of cover variables */
2633  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2634  int minweightidx, /**< index of variable in cover variables with minimum weight */
2635  int j /**< current index in cover variables */
2636  )
2637 {
2638  SCIP_Longint minweight;
2639  int i;
2640 
2641  assert(weights != NULL);
2642  assert(covervars != NULL);
2643  assert(ncovervars > 0);
2644 
2645  minweight = weights[covervars[minweightidx]];
2646 
2647  /* checks if all cover variables before index j have weight greater than minweight */
2648  for( i = 0; i < j; i++ )
2649  {
2650  assert(weights[covervars[i]] > minweight);
2651  if( weights[covervars[i]] <= minweight )
2652  return FALSE;
2653  }
2654 
2655  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2656  for( i = 0; i < j; i++ )
2657  {
2658  assert(coverweight - weights[covervars[i]] <= capacity);
2659  if( coverweight - weights[covervars[i]] > capacity )
2660  return FALSE;
2661  }
2662  return TRUE;
2663 }
2664 #endif
2665 
2666 
2667 /** 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$,
2668  * 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$
2669  */
2670 static
2672  SCIP* scip, /**< SCIP data structure */
2673  SCIP_Real* solvals, /**< solution values of all problem variables */
2674  int* covervars, /**< cover variables */
2675  int ncovervars, /**< number of cover variables */
2676  int* varsC1, /**< pointer to store variables in C1 */
2677  int* varsC2, /**< pointer to store variables in C2 */
2678  int* nvarsC1, /**< pointer to store number of variables in C1 */
2679  int* nvarsC2 /**< pointer to store number of variables in C2 */
2680  )
2681 {
2682  int j;
2683 
2684  assert(scip != NULL);
2685  assert(ncovervars >= 0);
2686  assert(solvals != NULL);
2687  assert(covervars != NULL);
2688  assert(varsC1 != NULL);
2689  assert(varsC2 != NULL);
2690  assert(nvarsC1 != NULL);
2691  assert(nvarsC2 != NULL);
2692 
2693  *nvarsC1 = 0;
2694  *nvarsC2 = 0;
2695  for( j = 0; j < ncovervars; j++ )
2696  {
2697  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2698 
2699  /* variable has solution value one */
2700  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2701  {
2702  varsC2[*nvarsC2] = covervars[j];
2703  (*nvarsC2)++;
2704  }
2705  /* variable has solution value less than one */
2706  else
2707  {
2708  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2709  varsC1[*nvarsC1] = covervars[j];
2710  (*nvarsC1)++;
2711  }
2712  }
2713  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2714 }
2715 
2716 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2717  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2718  */
2719 static
2721  SCIP* scip, /**< SCIP data structure */
2722  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2723  int* varsC1, /**< pointer to store variables in C1 */
2724  int* varsC2, /**< pointer to store variables in C2 */
2725  int* nvarsC1, /**< pointer to store number of variables in C1 */
2726  int* nvarsC2 /**< pointer to store number of variables in C2 */
2727  )
2729  SCIP_Real* sortkeysC2;
2730  int j;
2731 
2732  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2733  assert(*nvarsC2 > 0);
2734 
2735  /* allocates temporary memory */
2736  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2737 
2738  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2739  for( j = 0; j < *nvarsC2; j++ )
2740  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2741  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2742 
2743  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2744  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2745  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2746  {
2747  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2748  (*nvarsC1)++;
2749  (*nvarsC2)--;
2750  }
2751 
2752  /* frees temporary memory */
2753  SCIPfreeBufferArray(scip, &sortkeysC2);
2754 
2755  return SCIP_OKAY;
2756 }
2757 
2758 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2759 static
2761  SCIP* scip, /**< SCIP data structure */
2762  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2763  int* varsC1, /**< pointer to store variables in C1 */
2764  int* varsC2, /**< pointer to store variables in C2 */
2765  int* nvarsC1, /**< pointer to store number of variables in C1 */
2766  int* nvarsC2 /**< pointer to store number of variables in C2 */
2767  )
2769  SCIP_Real* sortkeysC2;
2770  int j;
2771 
2772  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2773  assert(*nvarsC2 > 0);
2774 
2775  /* allocates temporary memory */
2776  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2777 
2778  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2779  for( j = 0; j < *nvarsC2; j++ )
2780  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2781  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2782 
2783  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2784  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2785  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2786  (*nvarsC1)++;
2787  (*nvarsC2)--;
2788 
2789  /* frees temporary memory */
2790  SCIPfreeBufferArray(scip, &sortkeysC2);
2791 
2792  return SCIP_OKAY;
2793 }
2794 
2795 
2796 /** 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$
2797  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2798  * \f$F = (N \setminus C) \setminus F\f$
2799  */
2800 static
2802  SCIP* scip, /**< SCIP data structure */
2803  SCIP_Real* solvals, /**< solution values of all problem variables */
2804  int* noncovervars, /**< noncover variables */
2805  int nnoncovervars, /**< number of noncover variables */
2806  int* varsF, /**< pointer to store variables in F */
2807  int* varsR, /**< pointer to store variables in R */
2808  int* nvarsF, /**< pointer to store number of variables in F */
2809  int* nvarsR /**< pointer to store number of variables in R */
2810  )
2811 {
2812  int j;
2813 
2814  assert(scip != NULL);
2815  assert(nnoncovervars >= 0);
2816  assert(solvals != NULL);
2817  assert(noncovervars != NULL);
2818  assert(varsF != NULL);
2819  assert(varsR != NULL);
2820  assert(nvarsF != NULL);
2821  assert(nvarsR != NULL);
2822 
2823  *nvarsF = 0;
2824  *nvarsR = 0;
2825 
2826  for( j = 0; j < nnoncovervars; j++ )
2827  {
2828  /* variable has solution value zero */
2829  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2830  {
2831  varsR[*nvarsR] = noncovervars[j];
2832  (*nvarsR)++;
2833  }
2834  /* variable has solution value greater than zero */
2835  else
2836  {
2837  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2838  varsF[*nvarsF] = noncovervars[j];
2839  (*nvarsF)++;
2840  }
2841  }
2842  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2843 }
2844 
2845 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2846  * lifting procedure
2847  */
2848 static
2850  SCIP* scip, /**< SCIP data structure */
2851  SCIP_Real* solvals, /**< solution values of all problem variables */
2852  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2853  int* varsF, /**< pointer to store variables in F */
2854  int* varsC2, /**< pointer to store variables in C2 */
2855  int* varsR, /**< pointer to store variables in R */
2856  int nvarsF, /**< number of variables in F */
2857  int nvarsC2, /**< number of variables in C2 */
2858  int nvarsR /**< number of variables in R */
2859  )
2860 {
2861  SORTKEYPAIR** sortkeypairsF;
2862  SORTKEYPAIR* sortkeypairsFstore;
2863  SCIP_Real* sortkeysC2;
2864  SCIP_Real* sortkeysR;
2865  int j;
2866 
2867  assert(scip != NULL);
2868  assert(solvals != NULL);
2869  assert(weights != NULL);
2870  assert(varsF != NULL);
2871  assert(varsC2 != NULL);
2872  assert(varsR != NULL);
2873  assert(nvarsF >= 0);
2874  assert(nvarsC2 >= 0);
2875  assert(nvarsR >= 0);
2876 
2877  /* allocates temporary memory */
2878  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2879  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2880  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2881  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2882 
2883  /* gets sorting key for variables in F corresponding to the following lifting sequence
2884  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2885  * x*_1 >= x*_2 >= ... >= x*_|F|
2886  * in case of equality uses
2887  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2888  */
2889  for( j = 0; j < nvarsF; j++ )
2890  {
2891  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2892  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2893  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2894  }
2895 
2896  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2897  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2898  */
2899  for( j = 0; j < nvarsC2; j++ )
2900  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2901 
2902  /* gets sorting key for variables in R corresponding to the following lifting sequence
2903  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2904  */
2905  for( j = 0; j < nvarsR; j++ )
2906  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2907 
2908  /* sorts F, C2 and R */
2909  if( nvarsF > 0 )
2910  {
2911  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2912  }
2913  if( nvarsC2 > 0 )
2914  {
2915  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2916  }
2917  if( nvarsR > 0)
2918  {
2919  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2920  }
2921 
2922  /* frees temporary memory */
2923  SCIPfreeBufferArray(scip, &sortkeysR);
2924  SCIPfreeBufferArray(scip, &sortkeysC2);
2925  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2926  SCIPfreeBufferArray(scip, &sortkeypairsF);
2927 
2928  return SCIP_OKAY;
2929 }
2930 
2931 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2932  * for the sequential GUB wise lifting procedure
2933  */
2934 static
2936  SCIP* scip, /**< SCIP data structure */
2937  SCIP_GUBSET* gubset, /**< GUB set data structure */
2938  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2939  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2940  int* varsC1, /**< variables in C1 */
2941  int* varsC2, /**< variables in C2 */
2942  int* varsF, /**< variables in F */
2943  int* varsR, /**< variables in R */
2944  int nvarsC1, /**< number of variables in C1 */
2945  int nvarsC2, /**< number of variables in C2 */
2946  int nvarsF, /**< number of variables in F */
2947  int nvarsR, /**< number of variables in R */
2948  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2949  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2950  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2951  int* gubconsGR, /**< pointer to store GUBs in GR */
2952  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2953  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2954  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2955  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2956  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2957  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2958  )
2959 {
2960  SORTKEYPAIR** sortkeypairsGFC1;
2961  SORTKEYPAIR* sortkeypairsGFC1store;
2962  SCIP_Real* sortkeysC1;
2963  SCIP_Real* sortkeysC2;
2964  SCIP_Real* sortkeysR;
2965  int* nC1varsingubcons;
2966  int var;
2967  int gubconsidx;
2968  int varidx;
2969  int ngubconss;
2970  int ngubconsGOC1;
2971  int targetvar;
2972  int nvarsprocessed;
2973  int i;
2974  int j;
2975 
2976 #if GUBSPLITGNC1GUBS
2977  SCIP_Bool gubconswithF;
2978  int origngubconss;
2979  origngubconss = gubset->ngubconss;
2980 #endif
2981 
2982  assert(scip != NULL);
2983  assert(gubset != NULL);
2984  assert(solvals != NULL);
2985  assert(weights != NULL);
2986  assert(varsC1 != NULL);
2987  assert(varsC2 != NULL);
2988  assert(varsF != NULL);
2989  assert(varsR != NULL);
2990  assert(nvarsC1 > 0);
2991  assert(nvarsC2 >= 0);
2992  assert(nvarsF >= 0);
2993  assert(nvarsR >= 0);
2994  assert(gubconsGC1 != NULL);
2995  assert(gubconsGC2 != NULL);
2996  assert(gubconsGFC1 != NULL);
2997  assert(gubconsGR != NULL);
2998  assert(ngubconsGC1 != NULL);
2999  assert(ngubconsGC2 != NULL);
3000  assert(ngubconsGFC1 != NULL);
3001  assert(ngubconsGR != NULL);
3002  assert(maxgubvarssize != NULL);
3003 
3004  ngubconss = gubset->ngubconss;
3005  nvarsprocessed = 0;
3006  ngubconsGOC1 = 0;
3007 
3008  /* GUBs are categorized into different types according to the variables in volved
3009  * - GOC1: involves variables in C1 only -- no C2, R, F
3010  * - GNC1: involves variables in C1 and F (and R) -- no C2
3011  * - GF: involves variables in F (and R) only -- no C1, C2
3012  * - GC2: involves variables in C2 only -- no C1, R, F
3013  * - GR: involves variables in R only -- no C1, C2, F
3014  * which requires splitting GUBs in case they include variable in F and R.
3015  *
3016  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3017  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3018  * - second ordering level is
3019  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3020  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3021  * GR: non-increasing max{ a_k : k in GR_j}
3022  *
3023  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3024  * - GC1: GUBs of category GOC1 and GNC1
3025  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3026  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3027  */
3028 
3029  /* allocates temporary memory */
3030  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3031  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3032  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3033 
3034  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3035  * - F: non-increasing x*_j and non-increasing a_j in case of equality
3036  * - C2: non-increasing a_j
3037  * - R: non-increasing a_j
3038  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3039  */
3040 
3041  /* gets sorting key for variables in C1 corresponding to the following ordering
3042  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3043  */
3044  for( j = 0; j < nvarsC1; j++ )
3045  {
3046  /* gets sortkeys */
3047  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3048 
3049  /* update status of variable in its gub constraint */
3050  gubconsidx = gubset->gubconssidx[varsC1[j]];
3051  varidx = gubset->gubvarsidx[varsC1[j]];
3052  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3053  }
3054 
3055  /* gets sorting key for variables in F corresponding to the following ordering
3056  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3057  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3058  * and updates status of each variable in F in GUB set data structure
3059  */
3060  for( j = 0; j < nvarsF; j++ )
3061  {
3062  /* update status of variable in its gub constraint */
3063  gubconsidx = gubset->gubconssidx[varsF[j]];
3064  varidx = gubset->gubvarsidx[varsF[j]];
3065  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3066  }
3067 
3068  /* gets sorting key for variables in C2 corresponding to the following ordering
3069  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3070  * and updates status of each variable in F in GUB set data structure
3071  */
3072  for( j = 0; j < nvarsC2; j++ )
3073  {
3074  /* gets sortkeys */
3075  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3076 
3077  /* update status of variable in its gub constraint */
3078  gubconsidx = gubset->gubconssidx[varsC2[j]];
3079  varidx = gubset->gubvarsidx[varsC2[j]];
3080  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3081  }
3082 
3083  /* gets sorting key for variables in R corresponding to the following ordering
3084  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3085  * and updates status of each variable in F in GUB set data structure
3086  */
3087  for( j = 0; j < nvarsR; j++ )
3088  {
3089  /* gets sortkeys */
3090  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3091 
3092  /* update status of variable in its gub constraint */
3093  gubconsidx = gubset->gubconssidx[varsR[j]];
3094  varidx = gubset->gubvarsidx[varsR[j]];
3095  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3096  }
3097 
3098  /* sorts C1, F, C2 and R */
3099  assert(nvarsC1 > 0);
3100  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3101 
3102  if( nvarsC2 > 0 )
3103  {
3104  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3105  }
3106  if( nvarsR > 0)
3107  {
3108  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3109  }
3110 
3111  /* frees temporary memory */
3112  SCIPfreeBufferArray(scip, &sortkeysR);
3113  SCIPfreeBufferArray(scip, &sortkeysC2);
3114  SCIPfreeBufferArray(scip, &sortkeysC1);
3115 
3116  /* allocate and initialize temporary memory for sorting GUB constraints */
3117  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3118  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3119  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3120  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3121  for( i = 0; i < ngubconss; i++)
3122  {
3123  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3124  sortkeypairsGFC1[i]->key1 = 0.0;
3125  sortkeypairsGFC1[i]->key2 = 0.0;
3126  }
3127  *ngubconsGC1 = 0;
3128  *ngubconsGC2 = 0;
3129  *ngubconsGFC1 = 0;
3130  *ngubconsGR = 0;
3131  *ngubconscapexceed = 0;
3132  *maxgubvarssize = 0;
3133 
3134 #ifndef NDEBUG
3135  for( i = 0; i < gubset->ngubconss; i++ )
3136  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3137 #endif
3138 
3139  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3140  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3141  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3142  * non-increasing number of variables in F, and
3143  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3144  */
3145  for( i = 0; i < nvarsC1; i++ )
3146  {
3147  int nvarsC1capexceed;
3148 
3149  nvarsC1capexceed = 0;
3150 
3151  var = varsC1[i];
3152  gubconsidx = gubset->gubconssidx[var];
3153  varidx = gubset->gubvarsidx[var];
3154 
3155  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3156  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3157 
3158  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3159  * note that variables in C1 are already sorted by non-decreasing weigth
3160  */
3161  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3162  GUBsetSwapVars(scip, gubset, var, targetvar);
3163  nC1varsingubcons[gubconsidx]++;
3164 
3165  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3166  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3167  {
3168  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3169  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3170  continue;
3171  }
3172 
3173  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3174  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3175  */
3176 #if GUBSPLITGNC1GUBS
3177  gubconswithF = FALSE;
3178 #endif
3179  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3180  {
3181  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3182 
3183  /* C1-variable: update number of C1/capacity exceeding variables */
3184  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3185  {
3186  nvarsC1capexceed++;
3187  nvarsprocessed++;
3188  }
3189  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3190  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3191  {
3192 #if GUBSPLITGNC1GUBS
3193  gubconswithF = TRUE;
3194 #endif
3195  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3196 
3197  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3198  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3199  }
3200  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3201  {
3202  nvarsC1capexceed++;
3203  }
3204  else
3205  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3206  }
3207 
3208  /* update set of GC1 GUBs */
3209  gubconsGC1[*ngubconsGC1] = gubconsidx;
3210  (*ngubconsGC1)++;
3211 
3212  /* update maximum size of all GUB constraints */
3213  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3214  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3215 
3216  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3217  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3218  {
3219  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3220  ngubconsGOC1++;
3221  }
3222  else
3223  {
3224 #if GUBSPLITGNC1GUBS
3225  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3226  if( !gubconswithF )
3227  {
3228  GUBVARSTATUS movevarstatus;
3229 
3230  assert(gubset->ngubconss < gubset->nvars);
3231 
3232  /* create a new GUB for GR part of splitting */
3233  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3234  gubset->ngubconss++;
3235  ngubconss = gubset->ngubconss;
3236 
3237  /* fill GR with R variables in current GUB */
3238  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3239  {
3240  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3241  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3242  {
3243  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3244  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3245  gubconsidx, ngubconss-1) );
3246  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3247  movevarstatus;
3248  }
3249  }
3250 
3251  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3252  ngubconsGOC1++;
3253 
3254  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3255  gubconsGR[*ngubconsGR] = ngubconss-1;
3256  (*ngubconsGR)++;
3257  }
3258  /* variables in C1, F, and maybe R: GNC1 GUB */
3259  else
3260  {
3261  assert(gubconswithF);
3262 
3263  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3264  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3265  (*ngubconsGFC1)++;
3266  }
3267 #else
3268  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3269  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3270  (*ngubconsGFC1)++;
3271 #endif
3272  }
3273  }
3274 
3275  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3276  * are already sorted correctly
3277  */
3278  for( i = 0; i < nvarsC2; i++ )
3279  {
3280  var = varsC2[i];
3281  gubconsidx = gubset->gubconssidx[var];
3282  varidx = gubset->gubvarsidx[var];
3283 
3284  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3285  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3286  assert(varidx == 0);
3287  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3288  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3289 
3290  /* set status of GC2 GUB */
3291  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3292 
3293  /* update group of GC2 GUBs */
3294  gubconsGC2[*ngubconsGC2] = gubconsidx;
3295  (*ngubconsGC2)++;
3296 
3297  /* update maximum size of all GUB constraints */
3298  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3299  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3300 
3301  nvarsprocessed++;
3302  }
3303 
3304  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3305  * non-increasing number of variables in F, and
3306  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3307  */
3308  for( i = 0; i < nvarsF; i++ )
3309  {
3310  var = varsF[i];
3311  gubconsidx = gubset->gubconssidx[var];
3312  varidx = gubset->gubvarsidx[var];
3313 
3314  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3315  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3316 
3317  nvarsprocessed++;
3318 
3319  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3320  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3321  {
3322  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3323  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3324  continue;
3325  }
3326 
3327  /* set status of GF GUB */
3328  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3329 
3330  /* update sorting key of corresponding GFC1 GUB */
3331  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3332  {
3333  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3334  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3335 
3336  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3337  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3338  {
3339  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3340 
3341  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3342  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3343  }
3344  }
3345 
3346  /* update set of GFC1 GUBs */
3347  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3348  (*ngubconsGFC1)++;
3349 
3350  /* update maximum size of all GUB constraints */
3351  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3352  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3353  }
3354 
3355  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3356  * correctly
3357  */
3358  for( i = 0; i < nvarsR; i++ )
3359  {
3360  var = varsR[i];
3361  gubconsidx = gubset->gubconssidx[var];
3362  varidx = gubset->gubvarsidx[var];
3363 
3364  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3365  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3366 
3367  nvarsprocessed++;
3368 
3369  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3370  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3371  {
3372  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3373  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3374  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3375  continue;
3376  }
3377 
3378  /* set status of GR GUB */
3379  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3380 
3381  /* update set of GR GUBs */
3382  gubconsGR[*ngubconsGR] = gubconsidx;
3383  (*ngubconsGR)++;
3384 
3385  /* update maximum size of all GUB constraints */
3386  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3387  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3388  }
3389  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3390 
3391  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3392  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3393  assert(*ngubconscapexceed >= 0);
3394 #ifndef NDEBUG
3395  {
3396  int check;
3397 
3398  check = 0;
3399 
3400  /* remaining not handled GUBs should only contain capacity exceeding variables */
3401  for( i = 0; i < ngubconss; i++ )
3402  {
3403  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3404  check++;
3405  }
3406  assert(check == *ngubconscapexceed);
3407  }
3408 #endif
3409 
3410  /* sort GFCI GUBs according to computed sorting keys */
3411  if( (*ngubconsGFC1) > 0 )
3412  {
3413  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3414  }
3415 
3416  /* free temporary memory */
3417 #if GUBSPLITGNC1GUBS
3418  ngubconss = origngubconss;
3419 #endif
3420  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3421  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3422  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3423 
3424  return SCIP_OKAY;
3425 }
3426 
3427 /** enlarges minweight table to at least the given length */
3428 static
3430  SCIP* scip, /**< SCIP data structure */
3431  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3432  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3433  int* minweightssize, /**< pointer to current size of minweights table */
3434  int newlen /**< new length of minweights table */
3435  )
3436 {
3437  int j;
3438 
3439  assert(minweightsptr != NULL);
3440  assert(*minweightsptr != NULL);
3441  assert(minweightslen != NULL);
3442  assert(*minweightslen >= 0);
3443  assert(minweightssize != NULL);
3444  assert(*minweightssize >= 0);
3445 
3446  if( newlen > *minweightssize )
3447  {
3448  int newsize;
3449 
3450  /* reallocate table memory */
3451  newsize = SCIPcalcMemGrowSize(scip, newlen);
3452  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3453  *minweightssize = newsize;
3454  }
3455  assert(newlen <= *minweightssize);
3456 
3457  /* initialize new elements */
3458  for( j = *minweightslen; j < newlen; ++j )
3459  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3460  *minweightslen = newlen;
3461 
3462  return SCIP_OKAY;
3463 }
3464 
3465 /** lifts given inequality
3466  * sum_{j in M_1} x_j <= alpha_0
3467  * valid for
3468  * 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 }
3469  * to a valid inequality
3470  * 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
3471  * <= alpha_0 + sum_{j in M_2} alpha_j
3472  * for
3473  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3474  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3475  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3476  * extended weight inequalities.
3477  */
3478 static
3480  SCIP* scip, /**< SCIP data structure */
3481  SCIP_VAR** vars, /**< variables in knapsack constraint */
3482  int nvars, /**< number of variables in knapsack constraint */
3483  int ntightened, /**< number of variables with tightened upper bound */
3484  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3485  SCIP_Longint capacity, /**< capacity of knapsack */
3486  SCIP_Real* solvals, /**< solution values of all problem variables */
3487  int* varsM1, /**< variables in M_1 */
3488  int* varsM2, /**< variables in M_2 */
3489  int* varsF, /**< variables in F */
3490  int* varsR, /**< variables in R */
3491  int nvarsM1, /**< number of variables in M_1 */
3492  int nvarsM2, /**< number of variables in M_2 */
3493  int nvarsF, /**< number of variables in F */
3494  int nvarsR, /**< number of variables in R */
3495  int alpha0, /**< rights hand side of given valid inequality */
3496  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3497  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3498  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3499  )
3500 {
3501  SCIP_Longint* minweights;
3502  SCIP_Real* sortkeys;
3503  SCIP_Longint fixedonesweight;
3504  int minweightssize;
3505  int minweightslen;
3506  int j;
3507  int w;
3508 
3509  assert(scip != NULL);
3510  assert(vars != NULL);
3511  assert(nvars >= 0);
3512  assert(weights != NULL);
3513  assert(capacity >= 0);
3514  assert(solvals != NULL);
3515  assert(varsM1 != NULL);
3516  assert(varsM2 != NULL);
3517  assert(varsF != NULL);
3518  assert(varsR != NULL);
3519  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3520  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3521  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3522  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3523  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3524  assert(alpha0 >= 0);
3525  assert(liftcoefs != NULL);
3526  assert(cutact != NULL);
3527  assert(liftrhs != NULL);
3528 
3529  /* allocates temporary memory */
3530  minweightssize = nvarsM1 + 1;
3531  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3532  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3533 
3534  /* initializes data structures */
3535  BMSclearMemoryArray(liftcoefs, nvars);
3536  *cutact = 0.0;
3537 
3538  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3539  * and calculates activity of the current valid inequality
3540  */
3541  for( j = 0; j < nvarsM1; j++ )
3542  {
3543  assert(liftcoefs[varsM1[j]] == 0);
3544  liftcoefs[varsM1[j]] = 1;
3545  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3546  (*cutact) += solvals[varsM1[j]];
3547  }
3548 
3549  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3550 
3551  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3552  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3553  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3554  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3555  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3556  */
3557  minweights[0] = 0;
3558  for( w = 1; w <= nvarsM1; w++ )
3559  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3560  minweightslen = nvarsM1 + 1;
3561 
3562  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3563  fixedonesweight = 0;
3564  for( j = 0; j < nvarsM2; j++ )
3565  fixedonesweight += weights[varsM2[j]];
3566  assert(fixedonesweight >= 0);
3567 
3568  /* initializes right hand side of lifted valid inequality */
3569  *liftrhs = alpha0;
3570 
3571  /* sequentially up-lifts all variables in F: */
3572  for( j = 0; j < nvarsF; j++ )
3573  {
3574  SCIP_Longint weight;
3575  int liftvar;
3576  int liftcoef;
3577  int z;
3578 
3579  liftvar = varsF[j];
3580  weight = weights[liftvar];
3581  assert(liftvar >= 0 && liftvar < nvars);
3582  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3583  assert(weight > 0);
3584 
3585  /* knapsack problem is infeasible:
3586  * sets z = 0
3587  */
3588  if( capacity - fixedonesweight - weight < 0 )
3589  {
3590  z = 0;
3591  }
3592  /* knapsack problem is feasible:
3593  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3594  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3595  */
3596  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3597  {
3598  z = *liftrhs;
3599  }
3600  /* knapsack problem is feasible:
3601  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3602  */
3603  else
3604  {
3605  int left;
3606  int right;
3607  int middle;
3608 
3609  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3610  left = 0;
3611  right = (*liftrhs) + 1;
3612  while( left < right - 1 )
3613  {
3614  middle = (left + right) / 2;
3615  assert(0 <= middle && middle < minweightslen);
3616  if( minweights[middle] <= capacity - fixedonesweight - weight )
3617  left = middle;
3618  else
3619  right = middle;
3620  }
3621  assert(left == right - 1);
3622  assert(0 <= left && left < minweightslen);
3623  assert(minweights[left] <= capacity - fixedonesweight - weight );
3624  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3625 
3626  /* now z = left */
3627  z = left;
3628  assert(z <= *liftrhs);
3629  }
3630 
3631  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3632  liftcoef = (*liftrhs) - z;
3633  liftcoefs[liftvar] = liftcoef;
3634  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3635 
3636  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3637  if( liftcoef == 0 )
3638  continue;
3639 
3640  /* updates activity of current valid inequality */
3641  (*cutact) += liftcoef * solvals[liftvar];
3642 
3643  /* enlarges current minweight table:
3644  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3645  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3646  * and sets minweights_i[w] = infinity for
3647  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3648  */
3649  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3650 
3651  /* updates minweight table: minweight_i+1[w] =
3652  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3653  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3654  */
3655  for( w = minweightslen - 1; w >= 0; w-- )
3656  {
3657  SCIP_Longint min;
3658  if( w < liftcoef )
3659  {
3660  min = MIN(minweights[w], weight);
3661  minweights[w] = min;
3662  }
3663  else
3664  {
3665  assert(w >= liftcoef);
3666  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3667  minweights[w] = min;
3668  }
3669  }
3670  }
3671  assert(minweights[0] == 0);
3672 
3673  /* sequentially down-lifts all variables in M_2: */
3674  for( j = 0; j < nvarsM2; j++ )
3675  {
3676  SCIP_Longint weight;
3677  int liftvar;
3678  int liftcoef;
3679  int left;
3680  int right;
3681  int middle;
3682  int z;
3683 
3684  liftvar = varsM2[j];
3685  weight = weights[liftvar];
3686  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3687  assert(liftvar >= 0 && liftvar < nvars);
3688  assert(weight > 0);
3689 
3690  /* uses binary search to find
3691  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3692  */
3693  left = 0;
3694  right = minweightslen;
3695  while( left < right - 1 )
3696  {
3697  middle = (left + right) / 2;
3698  assert(0 <= middle && middle < minweightslen);
3699  if( minweights[middle] <= capacity - fixedonesweight + weight )
3700  left = middle;
3701  else
3702  right = middle;
3703  }
3704  assert(left == right - 1);
3705  assert(0 <= left && left < minweightslen);
3706  assert(minweights[left] <= capacity - fixedonesweight + weight );
3707  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3708 
3709  /* now z = left */
3710  z = left;
3711  assert(z >= *liftrhs);
3712 
3713  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3714  liftcoef = z - (*liftrhs);
3715  liftcoefs[liftvar] = liftcoef;
3716  assert(liftcoef >= 0);
3717 
3718  /* updates sum of weights of variables fixed to one */
3719  fixedonesweight -= weight;
3720 
3721  /* updates right-hand side of current valid inequality */
3722  (*liftrhs) += liftcoef;
3723  assert(*liftrhs >= alpha0);
3724 
3725  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3726  if( liftcoef == 0 )
3727  continue;
3728 
3729  /* updates activity of current valid inequality */
3730  (*cutact) += liftcoef * solvals[liftvar];
3731 
3732  /* enlarges current minweight table:
3733  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3734  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3735  * and sets minweights_i[w] = infinity for
3736  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3737  */
3738  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3739 
3740  /* updates minweight table: minweight_i+1[w] =
3741  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3742  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3743  */
3744  for( w = minweightslen - 1; w >= 0; w-- )
3745  {
3746  SCIP_Longint min;
3747  if( w < liftcoef )
3748  {
3749  min = MIN(minweights[w], weight);
3750  minweights[w] = min;
3751  }
3752  else
3753  {
3754  assert(w >= liftcoef);
3755  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3756  minweights[w] = min;
3757  }
3758  }
3759  }
3760  assert(fixedonesweight == 0);
3761  assert(*liftrhs >= alpha0);
3762 
3763  /* sequentially up-lifts all variables in R: */
3764  for( j = 0; j < nvarsR; j++ )
3765  {
3766  SCIP_Longint weight;
3767  int liftvar;
3768  int liftcoef;
3769  int z;
3770 
3771  liftvar = varsR[j];
3772  weight = weights[liftvar];
3773  assert(liftvar >= 0 && liftvar < nvars);
3774  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3775  assert(weight > 0);
3776  assert(capacity - weight >= 0);
3777  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3778 
3779  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3780  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3781  */
3782  if( minweights[*liftrhs] <= capacity - weight )
3783  {
3784  z = *liftrhs;
3785  }
3786  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3787  */
3788  else
3789  {
3790  int left;
3791  int right;
3792  int middle;
3793 
3794  left = 0;
3795  right = (*liftrhs) + 1;
3796  while( left < right - 1)
3797  {
3798  middle = (left + right) / 2;
3799  assert(0 <= middle && middle < minweightslen);
3800  if( minweights[middle] <= capacity - weight )
3801  left = middle;
3802  else
3803  right = middle;
3804  }
3805  assert(left == right - 1);
3806  assert(0 <= left && left < minweightslen);
3807  assert(minweights[left] <= capacity - weight );
3808  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3809 
3810  /* now z = left */
3811  z = left;
3812  assert(z <= *liftrhs);
3813  }
3814 
3815  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3816  liftcoef = (*liftrhs) - z;
3817  liftcoefs[liftvar] = liftcoef;
3818  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3819 
3820  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3821  if( liftcoef == 0 )
3822  continue;
3823 
3824  /* updates activity of current valid inequality */
3825  (*cutact) += liftcoef * solvals[liftvar];
3826 
3827  /* updates minweight table: minweight_i+1[w] =
3828  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3829  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3830  */
3831  for( w = *liftrhs; w >= 0; w-- )
3832  {
3833  SCIP_Longint min;
3834  if( w < liftcoef )
3835  {
3836  min = MIN(minweights[w], weight);
3837  minweights[w] = min;
3838  }
3839  else
3840  {
3841  assert(w >= liftcoef);
3842  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3843  minweights[w] = min;
3844  }
3845  }
3846  }
3847 
3848  /* frees temporary memory */
3849  SCIPfreeBufferArray(scip, &sortkeys);
3850  SCIPfreeBufferArray(scip, &minweights);
3851 
3852  return SCIP_OKAY;
3853 }
3854 
3855 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3856 static
3858  SCIP_Longint val1, /**< first value to add */
3859  SCIP_Longint val2 /**< second value to add */
3860  )
3861 {
3862  assert(val1 >= 0);
3863  assert(val2 >= 0);
3864 
3865  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3866  return SCIP_LONGINT_MAX;
3867  else
3868  {
3869  assert(val1 <= SCIP_LONGINT_MAX - val2);
3870  return (val1 + val2);
3871  }
3872 }
3873 
3874 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3875 static
3877  SCIP_Longint* minweights, /**< minweight table to compute */
3878  SCIP_Longint* finished, /**< given finished table */
3879  SCIP_Longint* unfinished, /**< given unfinished table */
3880  int minweightslen /**< length of minweight, finished, and unfinished tables */
3881  )
3882 {
3883  int w1;
3884  int w2;
3885 
3886  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3887  * note that finished and unfished arrays sorted by non-decreasing weight
3888  */
3889 
3890  /* initialize minweight with w2 = 0 */
3891  w2 = 0;
3892  assert(unfinished[w2] == 0);
3893  for( w1 = 0; w1 < minweightslen; w1++ )
3894  minweights[w1] = finished[w1];
3895 
3896  /* consider w2 = 1, ..., minweightslen-1 */
3897  for( w2 = 1; w2 < minweightslen; w2++ )
3898  {
3899  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3900  break;
3901 
3902  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3903  {
3904  SCIP_Longint temp;
3905 
3906  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3907  if( temp <= minweights[w1+w2] )
3908  minweights[w1+w2] = temp;
3909  }
3910  }
3911 }
3912 
3913 /** lifts given inequality
3914  * sum_{j in C_1} x_j <= alpha_0
3915  * valid for
3916  * 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;
3917  * sum_{j in Q_i} x_j <= 1, forall i in I }
3918  * to a valid inequality
3919  * 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
3920  * <= alpha_0 + sum_{j in C_2} alpha_j
3921  * for
3922  * 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 };
3923  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3924  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3925  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3926  */
3927 static
3929  SCIP* scip, /**< SCIP data structure */
3930  SCIP_GUBSET* gubset, /**< GUB set data structure */
3931  SCIP_VAR** vars, /**< variables in knapsack constraint */
3932  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3933  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3934  SCIP_Longint capacity, /**< capacity of knapsack */
3935  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3936  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3937  int* gubconsGC2, /**< GUBs in GC2 */
3938  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3939  int* gubconsGR, /**< GUBs in GR */
3940  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3941  int ngubconsGC2, /**< number of GUBs in GC2 */
3942  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3943  int ngubconsGR, /**< number of GUBs in GR */
3944  int alpha0, /**< rights hand side of given valid inequality */
3945  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3946  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3947  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3948  int maxgubvarssize /**< maximal size of GUB constraints */
3949  )
3950 {
3951  SCIP_Longint* minweights;
3952  SCIP_Longint* finished;
3953  SCIP_Longint* unfinished;
3954  int* gubconsGOC1;
3955  int* gubconsGNC1;
3956  int* liftgubvars;
3957  SCIP_Longint fixedonesweight;
3958  SCIP_Longint weight;
3959  SCIP_Longint weightdiff1;
3960  SCIP_Longint weightdiff2;
3961  SCIP_Longint min;
3962  int minweightssize;
3963  int minweightslen;
3964  int nvars;
3965  int varidx;
3966  int liftgubconsidx;
3967  int liftvar;
3968  int sumliftcoef;
3969  int liftcoef;
3970  int ngubconsGOC1;
3971  int ngubconsGNC1;
3972  int left;
3973  int right;
3974  int middle;
3975  int nliftgubvars;
3976  int tmplen;
3977  int tmpsize;
3978  int j;
3979  int k;
3980  int w;
3981  int z;
3982 #ifndef NDEBUG
3983  int ngubconss;
3984  int nliftgubC1;
3985 
3986  assert(gubset != NULL);
3987  ngubconss = gubset->ngubconss;
3988 #else
3989  assert(gubset != NULL);
3990 #endif
3991 
3992  nvars = gubset->nvars;
3993 
3994  assert(scip != NULL);
3995  assert(vars != NULL);
3996  assert(nvars >= 0);
3997  assert(weights != NULL);
3998  assert(capacity >= 0);
3999  assert(solvals != NULL);
4000  assert(gubconsGC1 != NULL);
4001  assert(gubconsGC2 != NULL);
4002  assert(gubconsGFC1 != NULL);
4003  assert(gubconsGR != NULL);
4004  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4005  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4006  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4007  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4008  assert(alpha0 >= 0);
4009  assert(liftcoefs != NULL);
4010  assert(cutact != NULL);
4011  assert(liftrhs != NULL);
4012 
4013  minweightssize = ngubconsGC1+1;
4014 
4015  /* allocates temporary memory */
4016  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4017  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4018  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4019  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4020  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4021  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4022 
4023  /* initializes data structures */
4024  BMSclearMemoryArray(liftcoefs, nvars);
4025  *cutact = 0.0;
4026 
4027  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4028  * valid inequality
4029  */
4030  ngubconsGOC1 = 0;
4031  ngubconsGNC1 = 0;
4032  for( j = 0; j < ngubconsGC1; j++ )
4033  {
4034  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4035  {
4036  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4037  ngubconsGOC1++;
4038  }
4039  else
4040  {
4041  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4042  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4043  ngubconsGNC1++;
4044  }
4045  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4046  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4047  {
4048  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4049  assert(varidx >= 0 && varidx < nvars);
4050  assert(liftcoefs[varidx] == 0);
4051 
4052  liftcoefs[varidx] = 1;
4053  (*cutact) += solvals[varidx];
4054  }
4055  assert(k >= 1);
4056  }
4057  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4058  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4059 
4060  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4061  * - finished_i[w] =
4062  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4063  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4064  * sum_{j in Q_k} x_j <= 1
4065  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4066  * - unfinished_i[w] =
4067  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4068  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4069  * sum_{j in Q_k} x_j <= 1
4070  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4071  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4072  */
4073 
4074  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4075  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4076  * 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
4077  * comes from the first variable in the GUB
4078  */
4079  assert(ngubconsGOC1 <= ngubconsGC1);
4080  finished[0] = 0;
4081  for( w = 1; w <= ngubconsGOC1; w++ )
4082  {
4083  liftgubconsidx = gubconsGOC1[w-1];
4084 
4085  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4086  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4087 
4088  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4089 
4090  assert(varidx >= 0 && varidx < nvars);
4091  assert(liftcoefs[varidx] == 1);
4092 
4093  min = weights[varidx];
4094  finished[w] = finished[w-1] + min;
4095 
4096 #ifndef NDEBUG
4097  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4098  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4099  {
4100  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4101  assert(varidx >= 0 && varidx < nvars);
4102  assert(liftcoefs[varidx] == 1);
4103  assert(weights[varidx] >= min);
4104  }
4105 #endif
4106  }
4107  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4108  finished[w] = SCIP_LONGINT_MAX;
4109 
4110  /* initialize unfinished table; note that variables in GNC1 GUBs
4111  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4112  * 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
4113  * comes from the first variable in the GUB
4114  */
4115  assert(ngubconsGNC1 <= ngubconsGC1);
4116  unfinished[0] = 0;
4117  for( w = 1; w <= ngubconsGNC1; w++ )
4118  {
4119  liftgubconsidx = gubconsGNC1[w-1];
4120 
4121  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4122  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4123 
4124  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4125 
4126  assert(varidx >= 0 && varidx < nvars);
4127  assert(liftcoefs[varidx] == 1);
4128 
4129  min = weights[varidx];
4130  unfinished[w] = unfinished[w-1] + min;
4131 
4132 #ifndef NDEBUG
4133  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4134  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4135  {
4136  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4137  assert(varidx >= 0 && varidx < nvars);
4138  assert(liftcoefs[varidx] == 1);
4139  assert(weights[varidx] >= min );
4140  }
4141 #endif
4142  }
4143  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4144  unfinished[w] = SCIP_LONGINT_MAX;
4145 
4146  /* initialize minweights table; note that variables in GC1 GUBs
4147  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4148  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4149  * consuming) because is it has to be build using weights from C1 only.
4150  */
4151  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4152  minweights[0] = 0;
4153  for( w = 1; w <= ngubconsGC1; w++ )
4154  {
4155  liftgubconsidx = gubconsGC1[w-1];
4156 
4157  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4158  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4159  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4160 
4161  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4162 
4163  assert(varidx >= 0 && varidx < nvars);
4164  assert(liftcoefs[varidx] == 1);
4165 
4166  min = weights[varidx];
4167  minweights[w] = minweights[w-1] + min;
4168 
4169 #ifndef NDEBUG
4170  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4171  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4172  {
4173  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4174  assert(varidx >= 0 && varidx < nvars);
4175  assert(liftcoefs[varidx] == 1);
4176  assert(weights[varidx] >= min);
4177  }
4178 #endif
4179  }
4180  minweightslen = ngubconsGC1 + 1;
4181 
4182  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4183  fixedonesweight = 0;
4184  for( j = 0; j < ngubconsGC2; j++ )
4185  {
4186  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4187 
4188  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4189  assert(varidx >= 0 && varidx < nvars);
4190  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4191 
4192  fixedonesweight += weights[varidx];
4193  }
4194  assert(fixedonesweight >= 0);
4195 
4196  /* initializes right hand side of lifted valid inequality */
4197  *liftrhs = alpha0;
4198 
4199  /* sequentially up-lifts all variables in GFC1 GUBs */
4200  for( j = 0; j < ngubconsGFC1; j++ )
4201  {
4202  liftgubconsidx = gubconsGFC1[j];
4203  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4204 
4205  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4206  * compute minweight table via updated unfinished table and aleady upto date finished table;
4207  */
4208  k = 0;
4209  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4210  {
4211  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4212  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4213  assert(ngubconsGNC1 > 0);
4214 
4215  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4216  * are considered for the lifting, i.e., not capacity exceeding
4217  */
4218  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4219  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4220  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4221  assert(k >= 1);
4222 
4223  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4224  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4225  */
4226  weight = weights[liftgubvars[0]];
4227 
4228  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4229  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4230  for( w = ngubconsGNC1-1; w >= 1; w-- )
4231  {
4232  weightdiff1 = weightdiff2;
4233  weightdiff2 = unfinished[w] - weight;
4234 
4235  if( unfinished[w] < weightdiff1 )
4236  unfinished[w] = weightdiff1;
4237  else
4238  break;
4239  }
4240  ngubconsGNC1--;
4241 
4242  /* computes minweights table by combining unfished and fished tables */
4243  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4244  assert(minweights[0] == 0);
4245  }
4246  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4247  * are therefore not in the unfinished table
4248  */
4249  else
4250  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4251 
4252 #ifndef NDEBUG
4253  nliftgubC1 = k;
4254 #endif
4255  nliftgubvars = k;
4256  sumliftcoef = 0;
4257 
4258  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4259  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4260  {
4261  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4262  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4263  {
4264  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4265  weight = weights[liftvar];
4266  assert(weight > 0);
4267  assert(liftvar >= 0 && liftvar < nvars);
4268  assert(capacity - weight >= 0);
4269 
4270  /* put variable into array of variables in GUB that are considered for the lifting,
4271  * i.e., not capacity exceeding
4272  */
4273  liftgubvars[nliftgubvars] = liftvar;
4274  nliftgubvars++;
4275 
4276  /* knapsack problem is infeasible:
4277  * sets z = 0
4278  */
4279  if( capacity - fixedonesweight - weight < 0 )
4280  {
4281  z = 0;
4282  }
4283  /* knapsack problem is feasible:
4284  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4285  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4286  */
4287  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4288  {
4289  z = *liftrhs;
4290  }
4291  /* knapsack problem is feasible:
4292  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4293  */
4294  else
4295  {
4296  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4297  left = 0;
4298  right = (*liftrhs) + 1;
4299  while( left < right - 1 )
4300  {
4301  middle = (left + right) / 2;
4302  assert(0 <= middle && middle < minweightslen);
4303  if( minweights[middle] <= capacity - fixedonesweight - weight )
4304  left = middle;
4305  else
4306  right = middle;
4307  }
4308  assert(left == right - 1);
4309  assert(0 <= left && left < minweightslen);
4310  assert(minweights[left] <= capacity - fixedonesweight - weight);
4311  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4312 
4313  /* now z = left */
4314  z = left;
4315  assert(z <= *liftrhs);
4316  }
4317 
4318  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4319  liftcoef = (*liftrhs) - z;
4320  liftcoefs[liftvar] = liftcoef;
4321  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4322 
4323  /* updates activity of current valid inequality */
4324  (*cutact) += liftcoef * solvals[liftvar];
4325 
4326  /* updates sum of all lifting coefficients in GUB */
4327  sumliftcoef += liftcoefs[liftvar];
4328  }
4329  else
4330  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4331  }
4332  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4333  assert(nliftgubvars > nliftgubC1);
4334 
4335  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4336  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4337  * not needed for GF GUBs
4338  */
4339  if( sumliftcoef == 0 )
4340  {
4341  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4342  {
4343  weight = weights[liftgubvars[0]];
4344  /* update finished table and minweights table by applying special case of
4345  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4346  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4347  */
4348  for( w = minweightslen-1; w >= 1; w-- )
4349  {
4350  SCIP_Longint tmpval;
4351 
4352  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4353  finished[w] = MIN(finished[w], tmpval);
4354 
4355  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4356  minweights[w] = MIN(minweights[w], tmpval);
4357  }
4358  }
4359  else
4360  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4361 
4362  continue;
4363  }
4364 
4365  /* enlarges current minweights tables(finished, unfinished, minweights):
4366  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4367  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4368  * and sets minweights_i[w] = infinity for
4369  * 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
4370  */
4371  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4372  tmpsize = minweightssize;
4373  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4374  tmplen = minweightslen;
4375  tmpsize = minweightssize;
4376  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4377  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4378 
4379  /* update finished table and minweight table;
4380  * note that instead of computing minweight table from updated finished and updated unfinished table again
4381  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4382  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4383  * not needed because only finished table changed at this point and the change was "adding" one weight)
4384  *
4385  * update formular for minweight table is: minweight_i+1[w] =
4386  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4387  * formular for finished table has the same pattern.
4388  */
4389  for( w = minweightslen-1; w >= 0; w-- )
4390  {
4391  SCIP_Longint minminweight;
4392  SCIP_Longint minfinished;
4393 
4394  for( k = 0; k < nliftgubvars; k++ )
4395  {
4396  liftcoef = liftcoefs[liftgubvars[k]];
4397  weight = weights[liftgubvars[k]];
4398 
4399  if( w < liftcoef )
4400  {
4401  minfinished = MIN(finished[w], weight);
4402  minminweight = MIN(minweights[w], weight);
4403 
4404  finished[w] = minfinished;
4405  minweights[w] = minminweight;
4406  }
4407  else
4408  {
4409  SCIP_Longint tmpval;
4410 
4411  assert(w >= liftcoef);
4412 
4413  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4414  minfinished = MIN(finished[w], tmpval);
4415 
4416  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4417  minminweight = MIN(minweights[w], tmpval);
4418 
4419  finished[w] = minfinished;
4420  minweights[w] = minminweight;
4421  }
4422  }
4423  }
4424  assert(minweights[0] == 0);
4425  }
4426  assert(ngubconsGNC1 == 0);
4427 
4428  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4429  * therefore, only work with minweight table from here on
4430  */
4431 
4432  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4433  for( j = 0; j < ngubconsGC2; j++ )
4434  {
4435  liftgubconsidx = gubconsGC2[j];
4436 
4437  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4438  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4439  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4440  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4441 
4442  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4443  weight = weights[liftvar];
4444 
4445  assert(liftvar >= 0 && liftvar < nvars);
4446  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4447  assert(weight > 0);
4448 
4449  /* uses binary search to find
4450  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4451  */
4452  left = 0;
4453  right = minweightslen;
4454  while( left < right - 1 )
4455  {
4456  middle = (left + right) / 2;
4457  assert(0 <= middle && middle < minweightslen);
4458  if( minweights[middle] <= capacity - fixedonesweight + weight )
4459  left = middle;
4460  else
4461  right = middle;
4462  }
4463  assert(left == right - 1);
4464  assert(0 <= left && left < minweightslen);
4465  assert(minweights[left] <= capacity - fixedonesweight + weight);
4466  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4467 
4468  /* now z = left */
4469  z = left;
4470  assert(z >= *liftrhs);
4471 
4472  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4473  liftcoef = z - (*liftrhs);
4474  liftcoefs[liftvar] = liftcoef;
4475  assert(liftcoef >= 0);
4476 
4477  /* updates sum of weights of variables fixed to one */
4478  fixedonesweight -= weight;
4479 
4480  /* updates right-hand side of current valid inequality */
4481  (*liftrhs) += liftcoef;
4482  assert(*liftrhs >= alpha0);
4483 
4484  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4485  if( liftcoef == 0 )
4486  continue;
4487 
4488  /* updates activity of current valid inequality */
4489  (*cutact) += liftcoef * solvals[liftvar];
4490 
4491  /* enlarges current minweight table:
4492  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4493  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4494  * and sets minweights_i[w] = infinity for
4495  * 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
4496  */
4497  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4498 
4499  /* updates minweight table: minweight_i+1[w] =
4500  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4501  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4502  */
4503  for( w = minweightslen - 1; w >= 0; w-- )
4504  {
4505  if( w < liftcoef )
4506  {
4507  min = MIN(minweights[w], weight);
4508  minweights[w] = min;
4509  }
4510  else
4511  {
4512  SCIP_Longint tmpval;
4513 
4514  assert(w >= liftcoef);
4515 
4516  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4517  min = MIN(minweights[w], tmpval);
4518  minweights[w] = min;
4519  }
4520  }
4521  }
4522  assert(fixedonesweight == 0);
4523  assert(*liftrhs >= alpha0);
4524 
4525  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4526  for( j = 0; j < ngubconsGR; j++ )
4527  {
4528  liftgubconsidx = gubconsGR[j];
4529 
4530  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4531  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4532 
4533  sumliftcoef = 0;
4534  nliftgubvars = 0;
4535  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4536  {
4537  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4538  {
4539  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4540  weight = weights[liftvar];
4541  assert(weight > 0);
4542  assert(liftvar >= 0 && liftvar < nvars);
4543  assert(capacity - weight >= 0);
4544  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4545 
4546  /* put variable into array of variables in GUB that are considered for the lifting,
4547  * i.e., not capacity exceeding
4548  */
4549  liftgubvars[nliftgubvars] = liftvar;
4550  nliftgubvars++;
4551 
4552  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4553  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4554  */
4555  if( minweights[*liftrhs] <= capacity - weight )
4556  {
4557  z = *liftrhs;
4558  }
4559  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4560  */
4561  else
4562  {
4563  left = 0;
4564  right = (*liftrhs) + 1;
4565  while( left < right - 1 )
4566  {
4567  middle = (left + right) / 2;
4568  assert(0 <= middle && middle < minweightslen);
4569  if( minweights[middle] <= capacity - weight )
4570  left = middle;
4571  else
4572  right = middle;
4573  }
4574  assert(left == right - 1);
4575  assert(0 <= left && left < minweightslen);
4576  assert(minweights[left] <= capacity - weight);
4577  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4578 
4579  /* now z = left */
4580  z = left;
4581  assert(z <= *liftrhs);
4582  }
4583  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4584  liftcoef = (*liftrhs) - z;
4585  liftcoefs[liftvar] = liftcoef;
4586  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4587 
4588  /* updates activity of current valid inequality */
4589  (*cutact) += liftcoef * solvals[liftvar];
4590 
4591  /* updates sum of all lifting coefficients in GUB */
4592  sumliftcoef += liftcoefs[liftvar];
4593  }
4594  else
4595  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4596  }
4597  assert(nliftgubvars >= 1); /* at least one variable is in R */
4598 
4599  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4600  if( sumliftcoef == 0 )
4601  continue;
4602 
4603  /* updates minweight table: minweight_i+1[w] =
4604  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4605  */
4606  for( w = *liftrhs; w >= 0; w-- )
4607  {
4608  for( k = 0; k < nliftgubvars; k++ )
4609  {
4610  liftcoef = liftcoefs[liftgubvars[k]];
4611  weight = weights[liftgubvars[k]];
4612 
4613  if( w < liftcoef )
4614  {
4615  min = MIN(minweights[w], weight);
4616  minweights[w] = min;
4617  }
4618  else
4619  {
4620  SCIP_Longint tmpval;
4621 
4622  assert(w >= liftcoef);
4623 
4624  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4625  min = MIN(minweights[w], tmpval);
4626  minweights[w] = min;
4627  }
4628  }
4629  }
4630  assert(minweights[0] == 0);
4631  }
4632 
4633  /* frees temporary memory */
4634  SCIPfreeBufferArray(scip, &minweights);
4635  SCIPfreeBufferArray(scip, &finished);
4636  SCIPfreeBufferArray(scip, &unfinished);
4637  SCIPfreeBufferArray(scip, &liftgubvars);
4638  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4639  SCIPfreeBufferArray(scip, &gubconsGNC1);
4640 
4641  return SCIP_OKAY;
4642 }
4643 
4644 /** lifts given minimal cover inequality
4645  * \f[
4646  * \sum_{j \in C} x_j \leq |C| - 1
4647  * \f]
4648  * valid for
4649  * \f[
4650  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4651  * \f]
4652  * to a valid inequality
4653  * \f[
4654  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4655  * \f]
4656  * for
4657  * \f[
4658  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4659  * \f]
4660  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4661  */
4662 static
4664  SCIP* scip, /**< SCIP data structure */
4665  SCIP_VAR** vars, /**< variables in knapsack constraint */
4666  int nvars, /**< number of variables in knapsack constraint */
4667  int ntightened, /**< number of variables with tightened upper bound */
4668  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4669  SCIP_Longint capacity, /**< capacity of knapsack */
4670  SCIP_Real* solvals, /**< solution values of all problem variables */
4671  int* covervars, /**< cover variables */
4672  int* noncovervars, /**< noncover variables */
4673  int ncovervars, /**< number of cover variables */
4674  int nnoncovervars, /**< number of noncover variables */
4675  SCIP_Longint coverweight, /**< weight of cover */
4676  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4677  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4678  )
4679 {
4680  SCIP_Longint* maxweightsums;
4681  SCIP_Longint* intervalends;
4682  SCIP_Longint* rhos;
4683  SCIP_Real* sortkeys;
4684  SCIP_Longint lambda;
4685  int j;
4686  int h;
4687 
4688  assert(scip != NULL);
4689  assert(vars != NULL);
4690  assert(nvars >= 0);
4691  assert(weights != NULL);
4692  assert(capacity >= 0);
4693  assert(solvals != NULL);
4694  assert(covervars != NULL);
4695  assert(noncovervars != NULL);
4696  assert(ncovervars > 0 && ncovervars <= nvars);
4697  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4698  assert(ncovervars + nnoncovervars == nvars - ntightened);
4699  assert(liftcoefs != NULL);
4700  assert(cutact != NULL);
4701 
4702  /* allocates temporary memory */
4703  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4704  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4705  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4706  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4707 
4708  /* initializes data structures */
4709  BMSclearMemoryArray(liftcoefs, nvars);
4710  *cutact = 0.0;
4711 
4712  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4713  * and calculates activity of current valid inequality
4714  */
4715  for( j = 0; j < ncovervars; j++ )
4716  {
4717  assert(liftcoefs[covervars[j]] == 0.0);
4718  liftcoefs[covervars[j]] = 1.0;
4719  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4720  (*cutact) += solvals[covervars[j]];
4721  }
4722  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4723 
4724  /* calculates weight excess of cover C */
4725  lambda = coverweight - capacity;
4726  assert(lambda > 0);
4727 
4728  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4729  maxweightsums[0] = 0;
4730  for( h = 1; h <= ncovervars; h++ )
4731  {
4732  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4733  intervalends[h-1] = maxweightsums[h] - lambda;
4734  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4735  }
4736 
4737  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4738  for( j = 0; j < nnoncovervars; j++ )
4739  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4740  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4741 
4742  /* calculates lifting coefficient for all variables in N\C */
4743  h = 0;
4744  for( j = 0; j < nnoncovervars; j++ )
4745  {
4746  int liftvar;
4747  SCIP_Longint weight;
4748  SCIP_Real liftcoef;
4749 
4750  liftvar = noncovervars[j];
4751  weight = weights[liftvar];
4752 
4753  while( intervalends[h] < weight )
4754  h++;
4755 
4756  if( h == 0 )
4757  liftcoef = h;
4758  else
4759  {
4760  if( weight <= intervalends[h-1] + rhos[h] )
4761  {
4762  SCIP_Real tmp1;
4763  SCIP_Real tmp2;
4764  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4765  tmp2 = (SCIP_Real) rhos[1];
4766  liftcoef = h - ( tmp1 / tmp2 );
4767  }
4768  else
4769  liftcoef = h;
4770  }
4771 
4772  /* sets lifting coefficient */
4773  assert(liftcoefs[liftvar] == 0.0);
4774  liftcoefs[liftvar] = liftcoef;
4775 
4776  /* updates activity of current valid inequality */
4777  (*cutact) += liftcoef * solvals[liftvar];
4778  }
4779 
4780  /* frees temporary memory */
4781  SCIPfreeBufferArray(scip, &rhos);
4782  SCIPfreeBufferArray(scip, &intervalends);
4783  SCIPfreeBufferArray(scip, &maxweightsums);
4784  SCIPfreeBufferArray(scip, &sortkeys);
4785 
4786  return SCIP_OKAY;
4787 }
4788 
4789 
4790 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4791  * given knapsack problem
4792 */
4793 static
4795  SCIP* scip, /**< SCIP data structure */
4796  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4797  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4798  SCIP_VAR** vars, /**< variables in knapsack constraint */
4799  int nvars, /**< number of variables in knapsack constraint */
4800  int ntightened, /**< number of variables with tightened upper bound */
4801  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4802  SCIP_Longint capacity, /**< capacity of knapsack */
4803  SCIP_Real* solvals, /**< solution values of all problem variables */
4804  int* mincovervars, /**< mincover variables */
4805  int* nonmincovervars, /**< nonmincover variables */
4806  int nmincovervars, /**< number of mincover variables */
4807  int nnonmincovervars, /**< number of nonmincover variables */
4808  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4809  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4810  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4811  int* ncuts /**< pointer to add up the number of found cuts */
4812  )
4813 {
4814  int* varsC1;
4815  int* varsC2;
4816  int* varsF;
4817  int* varsR;
4818  int nvarsC1;
4819  int nvarsC2;
4820  int nvarsF;
4821  int nvarsR;
4822  SCIP_Real cutact;
4823  int* liftcoefs;
4824  int liftrhs;
4825 
4826  assert( cutoff != NULL );
4827  *cutoff = FALSE;
4828 
4829  /* allocates temporary memory */
4830  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4831  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4832  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4833  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4834  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4835 
4836  /* 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
4837  * as follows
4838  * C_2 = { j in C : x*_j = 1 } and
4839  * C_1 = C\C_2
4840  */
4841  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4842  assert(nvarsC1 + nvarsC2 == nmincovervars);
4843  assert(nmincovervars > 0);
4844  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4845 
4846  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4847  if( nvarsC1 < 2 && nvarsC2 > 0)
4848  {
4849  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4850  assert(nvarsC1 >= 1);
4851  }
4852  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4853 
4854  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4855  * R = { j in N\C : x*_j = 0 } and
4856  * F = (N\C)\F
4857  */
4858  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4859  assert(nvarsF + nvarsR == nnonmincovervars);
4860  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4861 
4862  /* lift cuts without GUB information */
4863  if( gubset == NULL )
4864  {
4865  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4866  * lifting procedure
4867  */
4868  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4869 
4870  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4871  *
4872  * 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 }
4873  *
4874  * 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
4875  *
4876  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4877  *
4878  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4879  * up-lifting for the variables in R according to the second level lifting sequence
4880  */
4881  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4882  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4883  }
4884  /* lift cuts with GUB information */
4885  else
4886  {
4887  int* gubconsGC1;
4888  int* gubconsGC2;
4889  int* gubconsGFC1;
4890  int* gubconsGR;
4891  int ngubconsGC1;
4892  int ngubconsGC2;
4893  int ngubconsGFC1;
4894  int ngubconsGR;
4895  int ngubconss;
4896  int nconstightened;
4897  int maxgubvarssize;
4898 
4899  assert(nvars == gubset->nvars);
4900 
4901  ngubconsGC1 = 0;
4902  ngubconsGC2 = 0;
4903  ngubconsGFC1 = 0;
4904  ngubconsGR = 0;
4905  ngubconss = gubset->ngubconss;
4906  nconstightened = 0;
4907  maxgubvarssize = 0;
4908 
4909  /* allocates temporary memory */
4910  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4911  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4912  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4913  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4914 
4915  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4916  * the GUBs for the sequential GUB wise lifting procedure
4917  */
4918  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4919  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4920  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4921 
4922  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4923  *
4924  * 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,
4925  * sum_{j in Q_i} x_j <= 1, forall i in I }
4926  *
4927  * 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
4928  *
4929  * 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 },
4930  *
4931  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4932  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4933  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4934  */
4935  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4936  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4937  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4938 
4939  /* frees temporary memory */
4940  SCIPfreeBufferArray(scip, &gubconsGR);
4941  SCIPfreeBufferArray(scip, &gubconsGFC1);
4942  SCIPfreeBufferArray(scip, &gubconsGC2);
4943  SCIPfreeBufferArray(scip, &gubconsGC1);
4944  }
4945 
4946  /* checks, if lifting yielded a violated cut */
4947  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4948  {
4949  SCIP_ROW* row;
4950  char name[SCIP_MAXSTRLEN];
4951  int j;
4952 
4953  /* creates LP row */
4954  assert( cons == NULL || sepa == NULL );
4955  if ( cons != NULL )
4956  {
4957  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4958  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4959  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4960  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4961  }
4962  else if ( sepa != NULL )
4963  {
4964  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4965  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4966  }
4967  else
4968  {
4969  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4970  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4971  }
4972 
4973  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4974  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4975  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4976  for( j = 0; j < nvarsC1; j++ )
4977  {
4978  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4979  }
4980  for( j = 0; j < nvarsC2; j++ )
4981  {
4982  if( liftcoefs[varsC2[j]] > 0 )
4983  {
4984  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4985  }
4986  }
4987  for( j = 0; j < nvarsF; j++ )
4988  {
4989  if( liftcoefs[varsF[j]] > 0 )
4990  {
4991  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4992  }
4993  }
4994  for( j = 0; j < nvarsR; j++ )
4995  {
4996  if( liftcoefs[varsR[j]] > 0 )
4997  {
4998  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4999  }
5000  }
5001  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5002 
5003  /* checks, if cut is violated enough */
5004  if( SCIPisCutEfficacious(scip, sol, row) )
5005  {
5006  if( cons != NULL )
5007  {
5008  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5009  }
5010  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5011  (*ncuts)++;
5012  }
5013  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5014  }
5015 
5016  /* frees temporary memory */
5017  SCIPfreeBufferArray(scip, &liftcoefs);
5018  SCIPfreeBufferArray(scip, &varsR);
5019  SCIPfreeBufferArray(scip, &varsF);
5020  SCIPfreeBufferArray(scip, &varsC2);
5021  SCIPfreeBufferArray(scip, &varsC1);
5022 
5023  return SCIP_OKAY;
5024 }
5025 
5026 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5027 static
5029  SCIP* scip, /**< SCIP data structure */
5030  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5031  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5032  SCIP_VAR** vars, /**< variables in knapsack constraint */
5033  int nvars, /**< number of variables in knapsack constraint */
5034  int ntightened, /**< number of variables with tightened upper bound */
5035  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5036  SCIP_Longint capacity, /**< capacity of knapsack */
5037  SCIP_Real* solvals, /**< solution values of all problem variables */
5038  int* feassetvars, /**< variables in feasible set */
5039  int* nonfeassetvars, /**< variables not in feasible set */
5040  int nfeassetvars, /**< number of variables in feasible set */
5041  int nnonfeassetvars, /**< number of variables not in feasible set */
5042  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5043  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5044  int* ncuts /**< pointer to add up the number of found cuts */
5045  )
5046 {
5047  int* varsT1;
5048  int* varsT2;
5049  int* varsF;
5050  int* varsR;
5051  int* liftcoefs;
5052  SCIP_Real cutact;
5053  int nvarsT1;
5054  int nvarsT2;
5055  int nvarsF;
5056  int nvarsR;
5057  int liftrhs;
5058  int j;
5059 
5060  assert( cutoff != NULL );
5061  *cutoff = FALSE;
5062 
5063  /* allocates temporary memory */
5064  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5065  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5066  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5067  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5068  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5069 
5070  /* 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
5071  * as follows
5072  * T_2 = { j in T : x*_j = 1 } and
5073  * T_1 = T\T_2
5074  */
5075  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5076  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5077 
5078  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5079  if( nvarsT1 == 0 && nvarsT2 > 0)
5080  {
5081  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5082  assert(nvarsT1 == 1);
5083  }
5084  assert(nvarsT2 == 0 || nvarsT1 > 0);
5085 
5086  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5087  * R = { j in N\T : x*_j = 0 } and
5088  * F = (N\T)\F
5089  */
5090  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5091  assert(nvarsF + nvarsR == nnonfeassetvars);
5092  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5093 
5094  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5095  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5096  * is included in the sorting routine)
5097  */
5098  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5099 
5100  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5101  *
5102  * 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 }
5103  *
5104  * 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
5105  *
5106  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5107  *
5108  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5109  * up-lifting for the variabels in R according to the second level lifting sequence
5110  */
5111  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5112  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5113 
5114  /* checks, if lifting yielded a violated cut */
5115  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5116  {
5117  SCIP_ROW* row;
5118  char name[SCIP_MAXSTRLEN];
5119 
5120  /* creates LP row */
5121  assert( cons == NULL || sepa == NULL );
5122  if( cons != NULL )
5123  {
5124  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5125  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5126  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5127  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5128  }
5129  else if ( sepa != NULL )
5130  {
5131  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5132  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5133  }
5134  else
5135  {
5136  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5137  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5138  }
5139 
5140  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5141  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5142  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5143  for( j = 0; j < nvarsT1; j++ )
5144  {
5145  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5146  }
5147  for( j = 0; j < nvarsT2; j++ )
5148  {
5149  if( liftcoefs[varsT2[j]] > 0 )
5150  {
5151  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5152  }
5153  }
5154  for( j = 0; j < nvarsF; j++ )
5155  {
5156  if( liftcoefs[varsF[j]] > 0 )
5157  {
5158  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5159  }
5160  }
5161  for( j = 0; j < nvarsR; j++ )
5162  {
5163  if( liftcoefs[varsR[j]] > 0 )
5164  {
5165  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5166  }
5167  }
5168  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5169 
5170  /* checks, if cut is violated enough */
5171  if( SCIPisCutEfficacious(scip, sol, row) )
5172  {
5173  if( cons != NULL )
5174  {
5175  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5176  }
5177  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5178  (*ncuts)++;
5179  }
5180  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5181  }
5182 
5183  /* frees temporary memory */
5184  SCIPfreeBufferArray(scip, &liftcoefs);
5185  SCIPfreeBufferArray(scip, &varsR);
5186  SCIPfreeBufferArray(scip, &varsF);
5187  SCIPfreeBufferArray(scip, &varsT2);
5188  SCIPfreeBufferArray(scip, &varsT1);
5189 
5190  return SCIP_OKAY;
5191 }
5192 
5193 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5194 static
5196  SCIP* scip, /**< SCIP data structure */
5197  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5198  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5199  SCIP_VAR** vars, /**< variables in knapsack constraint */
5200  int nvars, /**< number of variables in knapsack constraint */
5201  int ntightened, /**< number of variables with tightened upper bound */
5202  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5203  SCIP_Longint capacity, /**< capacity of knapsack */
5204  SCIP_Real* solvals, /**< solution values of all problem variables */
5205  int* mincovervars, /**< mincover variables */
5206  int* nonmincovervars, /**< nonmincover variables */
5207  int nmincovervars, /**< number of mincover variables */
5208  int nnonmincovervars, /**< number of nonmincover variables */
5209  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5210  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5211  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5212  int* ncuts /**< pointer to add up the number of found cuts */
5213  )
5214 {
5215  SCIP_Real* realliftcoefs;
5216  SCIP_Real cutact;
5217  int liftrhs;
5218 
5219  assert( cutoff != NULL );
5220  *cutoff = FALSE;
5221  cutact = 0.0;
5222 
5223  /* allocates temporary memory */
5224  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5225 
5226  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5227  *
5228  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5229  *
5230  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5231  *
5232  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5233  *
5234  * uses superadditive up-lifting for the variables in N\C.
5235  */
5236  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5237  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5238  liftrhs = nmincovervars - 1;
5239 
5240  /* checks, if lifting yielded a violated cut */
5241  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5242  {
5243  SCIP_ROW* row;
5244  char name[SCIP_MAXSTRLEN];
5245  int j;
5246 
5247  /* creates LP row */
5248  assert( cons == NULL || sepa == NULL );
5249  if ( cons != NULL )
5250  {
5251  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5252  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5253  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5254  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5255  }
5256  else if ( sepa != NULL )
5257  {
5258  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5259  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5260  }
5261  else
5262  {
5263  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5264  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5265  }
5266 
5267  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5268  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5269  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5270  for( j = 0; j < nmincovervars; j++ )
5271  {
5272  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5273  }
5274  for( j = 0; j < nnonmincovervars; j++ )
5275  {
5276  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5277  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5278  {
5279  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5280  }
5281  }
5282  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5283 
5284  /* checks, if cut is violated enough */
5285  if( SCIPisCutEfficacious(scip, sol, row) )
5286  {
5287  if( cons != NULL )
5288  {
5289  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5290  }
5291  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5292  (*ncuts)++;
5293  }
5294  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5295  }
5296 
5297  /* frees temporary memory */
5298  SCIPfreeBufferArray(scip, &realliftcoefs);
5299 
5300  return SCIP_OKAY;
5301 }
5302 
5303 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5304  * 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
5305  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5306  * note that all variables with x*_j = 1 will be removed last
5307  */
5308 static
5310  SCIP* scip, /**< SCIP data structure */
5311  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5312  SCIP_Longint capacity, /**< capacity of knapsack */
5313  SCIP_Real* solvals, /**< solution values of all problem variables */
5314  int* covervars, /**< pointer to store cover variables */
5315  int* noncovervars, /**< pointer to store noncover variables */
5316  int* ncovervars, /**< pointer to store number of cover variables */
5317  int* nnoncovervars, /**< pointer to store number of noncover variables */
5318  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5319  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5320  )
5321 {
5322  SORTKEYPAIR** sortkeypairs;
5323  SORTKEYPAIR** sortkeypairssorted;
5324  SCIP_Longint minweight;
5325  int nsortkeypairs;
5326  int minweightidx;
5327  int j;
5328  int k;
5329 
5330  assert(scip != NULL);
5331  assert(covervars != NULL);
5332  assert(noncovervars != NULL);
5333  assert(ncovervars != NULL);
5334  assert(*ncovervars > 0);
5335  assert(nnoncovervars != NULL);
5336  assert(*nnoncovervars >= 0);
5337  assert(coverweight != NULL);
5338  assert(*coverweight > 0);
5339  assert(*coverweight > capacity);
5340 
5341  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5342  * order */
5343  nsortkeypairs = *ncovervars;
5344  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5345  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5346 
5347  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5348  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5349  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5350  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5351  */
5352  assert(*ncovervars == nsortkeypairs);
5353  if( modtransused )
5354  {
5355  for( j = 0; j < *ncovervars; j++ )
5356  {
5357  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5358  sortkeypairssorted[j] = sortkeypairs[j];
5359 
5360  sortkeypairs[j]->key1 = solvals[covervars[j]];
5361  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5362  }
5363  }
5364  else
5365  {
5366  for( j = 0; j < *ncovervars; j++ )
5367  {
5368  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5369  sortkeypairssorted[j] = sortkeypairs[j];
5370 
5371  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5372  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5373  }
5374  }
5375  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5376 
5377  /* gets j' with a_j' = min{ a_j : j in C } */
5378  minweightidx = 0;
5379  minweight = weights[covervars[minweightidx]];
5380  for( j = 1; j < *ncovervars; j++ )
5381  {
5382  if( weights[covervars[j]] <= minweight )
5383  {
5384  minweightidx = j;
5385  minweight = weights[covervars[minweightidx]];
5386  }
5387  }
5388  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5389  assert(minweight > 0 && minweight <= *coverweight);
5390 
5391  j = 0;
5392  /* removes variables from C until the remaining variables form a minimal cover */
5393  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5394  {
5395  assert(minweightidx >= j);
5396  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5397 
5398  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5399  if( (*coverweight) - weights[covervars[j]] <= capacity )
5400  {
5401  ++j;
5402  continue;
5403  }
5404 
5405  /* adds j to N\C */
5406  noncovervars[*nnoncovervars] = covervars[j];
5407  (*nnoncovervars)++;
5408 
5409  /* removes j from C */
5410  (*coverweight) -= weights[covervars[j]];
5411  for( k = j; k < (*ncovervars) - 1; k++ )
5412  covervars[k] = covervars[k+1];
5413  (*ncovervars)--;
5414 
5415  /* updates j' with a_j' = min{ a_j : j in C } */
5416  if( j == minweightidx )
5417  {
5418  minweightidx = 0;
5419  minweight = weights[covervars[minweightidx]];
5420  for( k = 1; k < *ncovervars; k++ )
5421  {
5422  if( weights[covervars[k]] <= minweight )
5423  {
5424  minweightidx = k;
5425  minweight = weights[covervars[minweightidx]];
5426  }
5427  }
5428  assert(minweight > 0 && minweight <= *coverweight);
5429  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5430  }
5431  else
5432  {
5433  assert(minweightidx > j);
5434  minweightidx--;
5435  }
5436  /* j needs to stay the same */
5437  }
5438  assert((*coverweight) > capacity);
5439  assert((*coverweight) - minweight <= capacity);
5440 
5441  /* frees temporary memory */
5442  for( j = nsortkeypairs-1; j >= 0; j-- )
5443  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5444  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5445  SCIPfreeBufferArray(scip, &sortkeypairs);
5446 
5447  return SCIP_OKAY;
5448 }
5449 
5450 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5451  * they were chosen to be in C_init:
5452  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5453  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5454  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5455  * and all subsequent feasible sets.
5456  */
5457 static
5459  SCIP* scip, /**< SCIP data structure */
5460  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5461  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5462  SCIP_VAR** vars, /**< variables in knapsack constraint */
5463  int nvars, /**< number of variables in knapsack constraint */
5464  int ntightened, /**< number of variables with tightened upper bound */
5465  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5466  SCIP_Longint capacity, /**< capacity of knapsack */
5467  SCIP_Real* solvals, /**< solution values of all problem variables */
5468  int* covervars, /**< pointer to store cover variables */
5469  int* noncovervars, /**< pointer to store noncover variables */
5470  int* ncovervars, /**< pointer to store number of cover variables */
5471  int* nnoncovervars, /**< pointer to store number of noncover variables */
5472  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5473  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5474  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5475  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5476  int* ncuts /**< pointer to add up the number of found cuts */
5477  )
5478 {
5479  SCIP_Real* sortkeys;
5480  int j;
5481  int k;
5482 
5483  assert(scip != NULL);
5484  assert(covervars != NULL);
5485  assert(noncovervars != NULL);
5486  assert(ncovervars != NULL);
5487  assert(*ncovervars > 0);
5488  assert(nnoncovervars != NULL);
5489  assert(*nnoncovervars >= 0);
5490  assert(coverweight != NULL);
5491  assert(*coverweight > 0);
5492  assert(*coverweight > capacity);
5493  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5494  assert(cutoff != NULL);
5495 
5496  *cutoff = FALSE;
5497 
5498  /* allocates temporary memory */
5499  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5500 
5501  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5502  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5503  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5504  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5505  */
5506  if( modtransused )
5507  {
5508  for( j = 0; j < *ncovervars; j++ )
5509  {
5510  sortkeys[j] = solvals[covervars[j]];
5511  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5512  }
5513  }
5514  else
5515  {
5516  for( j = 0; j < *ncovervars; j++ )
5517  {
5518  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5519  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5520  }
5521  }
5522  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5523 
5524  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5525  * in addition to an extended weight inequality this gives cardinality inequalities */
5526  while( *ncovervars >= 2 )
5527  {
5528  /* adds first element of C_init to N\C_init */
5529  noncovervars[*nnoncovervars] = covervars[0];
5530  (*nnoncovervars)++;
5531 
5532  /* removes first element from C_init */
5533  (*coverweight) -= weights[covervars[0]];
5534  for( k = 0; k < (*ncovervars) - 1; k++ )
5535  covervars[k] = covervars[k+1];
5536  (*ncovervars)--;
5537 
5538  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5539  if( (*coverweight) <= capacity )
5540  {
5541  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5542  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5543  }
5544 
5545  /* stop if cover is too large */
5546  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5547  break;
5548  }
5549 
5550  /* frees temporary memory */
5551  SCIPfreeBufferArray(scip, &sortkeys);
5552 
5553  return SCIP_OKAY;
5554 }
5555 
5556 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5558  SCIP* scip, /**< SCIP data structure */
5559  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5560  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5561  SCIP_VAR** vars, /**< variables in knapsack constraint */
5562  int nvars, /**< number of variables in knapsack constraint */
5563  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5564  SCIP_Longint capacity, /**< capacity of knapsack */
5565  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5566  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5567  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5568  int* ncuts /**< pointer to add up the number of found cuts */
5569  )
5570 {
5571  SCIP_Real* solvals;
5572  int* covervars;
5573  int* noncovervars;
5574  SCIP_Bool coverfound;
5575  SCIP_Bool fractional;
5576  SCIP_Bool modtransused;
5577  SCIP_Longint coverweight;
5578  int ncovervars;
5579  int nnoncovervars;
5580  int ntightened;
5581 
5582  assert(scip != NULL);
5583  assert(capacity >= 0);
5584  assert(cutoff != NULL);
5585  assert(ncuts != NULL);
5586 
5587  *cutoff = FALSE;
5588 
5589  if( nvars == 0 )
5590  return SCIP_OKAY;
5591 
5592  assert(vars != NULL);
5593  assert(nvars > 0);
5594  assert(weights != NULL);
5595 
5596  /* increase age of constraint (age is reset to zero, if a cut was found) */
5597  if( cons != NULL )
5598  {
5599  SCIP_CALL( SCIPincConsAge(scip, cons) );
5600  }
5601 
5602  /* allocates temporary memory */
5603  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5604  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5605  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5606 
5607  /* gets solution values of all problem variables */
5608  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5609 
5610 #ifdef SCIP_DEBUG
5611  {
5612  int i;
5613 
5614  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5615  cons == NULL ? "-" : SCIPconsGetName(cons));
5616  for( i = 0; i < nvars; ++i )
5617  {
5618  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5619  }
5620  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5621  }
5622 #endif
5623 
5624  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5625  */
5626  if( usegubs )
5627  {
5628  SCIP_GUBSET* gubset;
5629 
5630  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5631 
5632  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5633  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5634 
5635  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5636  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5637  assert(gubset->ngubconss <= nvars);
5638 
5639  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5640  * MODIFIED transformed separation problem and taking into account the following fixing:
5641  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5642  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5643  * if one exists
5644  */
5645  modtransused = TRUE;
5646  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5647  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5648 
5649  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5650 
5651  /* if x* is not fractional we stop the separation routine */
5652  if( !fractional )
5653  {
5654  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5655 
5656  /* frees memory for GUB set data structure */
5657  GUBsetFree(scip, &gubset);
5658 
5659  goto TERMINATE;
5660  }
5661 
5662  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5663  if( coverfound )
5664  {
5665  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5666  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5667  */
5668  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5669  &nnoncovervars, &coverweight, modtransused) );
5670 
5671  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5672  if( gubset->ngubconss < nvars )
5673  {
5674  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5675  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5676  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5677  }
5678  else
5679  {
5680  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5681  * GUB information
5682  */
5683  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5684  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5685  }
5686  }
5687 
5688  /* frees memory for GUB set data structure */
5689  GUBsetFree(scip, &gubset);
5690  }
5691  else
5692  {
5693  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5694  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5695  */
5696 
5697  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5698  * MODIFIED transformed separation problem and taking into account the following fixing:
5699  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5700  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5701  * if one exists
5702  */
5703  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5704  modtransused = TRUE;
5705  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5706  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5707  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5708 
5709  /* if x* is not fractional we stop the separation routine */
5710  if( !fractional )
5711  goto TERMINATE;
5712 
5713  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5714  if( coverfound )
5715  {
5716  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5717  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5718  */
5719  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5720  &nnoncovervars, &coverweight, modtransused) );
5721 
5722  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5723  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5724  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5725 
5726  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5727  {
5728  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5729  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5730  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5731  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5732  }
5733  }
5734  }
5735 
5736  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5737  if ( ! (*cutoff) )
5738  {
5739  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5740  * transformed separation problem and taking into account the following fixing:
5741  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5742  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5743  * if one exists
5744  */
5745  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5746  modtransused = FALSE;
5747  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5748  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5749  assert(fractional);
5750  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5751 
5752  /* if no cover was found we stop the separation routine */
5753  if( coverfound )
5754  {
5755  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5756  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5757  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5758  */
5759  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5760  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5761  }
5762  }
5763 
5764  TERMINATE:
5765  /* frees temporary memory */
5766  SCIPfreeBufferArray(scip, &noncovervars);
5767  SCIPfreeBufferArray(scip, &covervars);
5768  SCIPfreeBufferArray(scip, &solvals);
5769 
5770  return SCIP_OKAY;
5771 }
5772 
5773 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5775  SCIP* scip, /**< SCIP data structure */
5776  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5777  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5778  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5779  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5780  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5781  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5782  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5783  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5784  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5785  int* ncuts /**< pointer to add up the number of found cuts */
5786  )
5787 {
5788  SCIP_VAR** binvars;
5789  SCIP_VAR** consvars;
5790  SCIP_Real* binvals;
5791  SCIP_Longint* consvals;
5792  SCIP_Longint minact;
5793  SCIP_Longint maxact;
5794  SCIP_Real intscalar;
5795  SCIP_Bool success;
5796  int nbinvars;
5797  int nconsvars;
5798  int i;
5799 
5800  int* tmpindices;
5801  int tmp;
5802  SCIP_CONSHDLR* conshdlr;
5803  SCIP_CONSHDLRDATA* conshdlrdata;
5804  SCIP_Bool noknapsackconshdlr;
5805  SCIP_Bool usegubs;
5806 
5807  assert(nknapvars > 0);
5808  assert(knapvars != NULL);
5809  assert(cutoff != NULL);
5810 
5811  tmpindices = NULL;
5812 
5813  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5814  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5815 
5816  binvars = SCIPgetVars(scip);
5817 
5818  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5819  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5820 
5821  *cutoff = FALSE;
5822 
5823  if( nbinvars == 0 )
5824  return SCIP_OKAY;
5825 
5826  /* set up data structures */
5827  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5828  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5829 
5830  /* get conshdlrdata to use cleared memory */
5831  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5832  if( conshdlr == NULL )
5833  {
5834  noknapsackconshdlr = TRUE;
5835  usegubs = DEFAULT_USEGUBS;
5836 
5837  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5838  BMSclearMemoryArray(binvals, nbinvars);
5839  }
5840  else
5841  {
5842  noknapsackconshdlr = FALSE;
5843  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5844  assert(conshdlrdata != NULL);
5845  usegubs = conshdlrdata->usegubs;
5846 
5847  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5848 
5849  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5850  * change their types to SCIP_VARTYPE_BINARY during presolving
5851  */
5852  if( conshdlrdata->reals1size == 0 )
5853  {
5854  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5855  conshdlrdata->reals1size = 1;
5856  conshdlrdata->reals1[0] = 0.0;
5857  }
5858 
5859  assert(conshdlrdata->reals1size > 0);
5860 
5861  /* next if condition should normally not be true, because it means that presolving has created more binary
5862  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5863  * transform all integers into their binary representation then it maybe happens
5864  */
5865  if( conshdlrdata->reals1size < nbinvars )
5866  {
5867  int oldsize = conshdlrdata->reals1size;
5868 
5869  conshdlrdata->reals1size = nbinvars;
5870  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5871  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5872  }
5873  binvals = conshdlrdata->reals1;
5874 
5875  /* check for cleared array, all entries have to be zero */
5876 #ifndef NDEBUG
5877  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5878  {
5879  assert(binvals[tmp] == 0);
5880  }
5881 #endif
5882  }
5883 
5884  tmp = 0;
5885 
5886  /* relax continuous knapsack constraint:
5887  * 1. make all variables binary:
5888  * if x_j is continuous or integer variable substitute:
5889  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5890  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5891  * 2. convert coefficients of all variables to positive integers:
5892  * - scale all coefficients a_j to a~_j integral
5893  * - substitute x~_j = 1 - x_j if a~_j < 0
5894  */
5895 
5896  /* replace integer and continuous variables with binary variables */
5897  for( i = 0; i < nknapvars; i++ )
5898  {
5899  SCIP_VAR* var;
5900 
5901  var = knapvars[i];
5902 
5903  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5904  {
5905  SCIP_Real solval;
5906  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5907 
5908  solval = SCIPgetSolVal(scip, sol, var);
5909 
5910  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5911  if( SCIPisFeasLT(scip, solval, 0.0 )
5912  || SCIPisFeasGT(scip, solval, 1.0) )
5913  {
5914  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5915  solval, SCIPvarGetName(var));
5916  goto TERMINATE;
5917  }
5918 
5919  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5920  if( !noknapsackconshdlr )
5921  {
5922  assert(tmpindices != NULL);
5923 
5924  tmpindices[tmp] = SCIPvarGetProbindex(var);
5925  ++tmp;
5926  }
5927  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5928  }
5929  else if( valscale * knapvals[i] > 0.0 )
5930  {
5931  SCIP_VAR** zvlb;
5932  SCIP_Real* bvlb;
5933  SCIP_Real* dvlb;
5934  SCIP_Real bestlbsol;
5935  int bestlbtype;
5936  int nvlb;
5937  int j;
5938 
5939  /* a_j > 0: substitution with lb or vlb */
5940  nvlb = SCIPvarGetNVlbs(var);
5941  zvlb = SCIPvarGetVlbVars(var);
5942  bvlb = SCIPvarGetVlbCoefs(var);
5943  dvlb = SCIPvarGetVlbConstants(var);
5944 
5945  /* search for lb or vlb with maximal bound value */
5946  bestlbsol = SCIPvarGetLbGlobal(var);
5947  bestlbtype = -1;
5948  for( j = 0; j < nvlb; j++ )
5949  {
5950  /* use only numerical stable vlb with binary variable z */
5951  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5952  {
5953  SCIP_Real vlbsol;
5954 
5955  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5956  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5957  {
5958  *cutoff = TRUE;
5959  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5961  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5962  goto TERMINATE;
5963  }
5964 
5965  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5966  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5967  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5968  {
5969  bestlbsol = vlbsol;
5970  bestlbtype = j;
5971  }
5972  }
5973  }
5974 
5975  /* if no lb or vlb with binary variable was found, we have to abort */
5976  if( SCIPisInfinity(scip, -bestlbsol) )
5977  goto TERMINATE;
5978 
5979  if( bestlbtype == -1 )
5980  {
5981  rhs -= valscale * knapvals[i] * bestlbsol;
5982  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5983  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5984  }
5985  else
5986  {
5987  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5988  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5989  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5990 
5991  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5992  goto TERMINATE;
5993 
5994  if( !noknapsackconshdlr )
5995  {
5996  assert(tmpindices != NULL);
5997 
5998  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5999  ++tmp;
6000  }
6001  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6002  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6003  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6004  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6005  }
6006  }
6007  else
6008  {
6009  SCIP_VAR** zvub;
6010  SCIP_Real* bvub;
6011  SCIP_Real* dvub;
6012  SCIP_Real bestubsol;
6013  int bestubtype;
6014  int nvub;
6015  int j;
6016 
6017  assert(valscale * knapvals[i] < 0.0);
6018 
6019  /* a_j < 0: substitution with ub or vub */
6020  nvub = SCIPvarGetNVubs(var);
6021  zvub = SCIPvarGetVubVars(var);
6022  bvub = SCIPvarGetVubCoefs(var);
6023  dvub = SCIPvarGetVubConstants(var);
6024 
6025  /* search for ub or vub with minimal bound value */
6026  bestubsol = SCIPvarGetUbGlobal(var);
6027  bestubtype = -1;
6028  for( j = 0; j < nvub; j++ )
6029  {
6030  /* use only numerical stable vub with active binary variable z */
6031  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6032  {
6033  SCIP_Real vubsol;
6034 
6035  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6036  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6037  {
6038  *cutoff = TRUE;
6039  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6041  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6042  goto TERMINATE;
6043  }
6044 
6045  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6046  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6047  if( SCIPisLE(scip, vubsol, bestubsol) )
6048  {
6049  bestubsol = vubsol;
6050  bestubtype = j;
6051  }
6052  }
6053  }
6054 
6055  /* if no ub or vub with binary variable was found, we have to abort */
6056  if( SCIPisInfinity(scip, bestubsol) )
6057  goto TERMINATE;
6058 
6059  if( bestubtype == -1 )
6060  {
6061  rhs -= valscale * knapvals[i] * bestubsol;
6062  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6063  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6064  }
6065  else
6066  {
6067  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6068  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6069  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6070 
6071  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6072  goto TERMINATE;
6073 
6074  if( !noknapsackconshdlr )
6075  {
6076  assert(tmpindices != NULL);
6077 
6078  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6079  ++tmp;
6080  }
6081  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6082  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6083  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6084  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6085  }
6086  }
6087  }
6088 
6089  /* convert coefficients of all (now binary) variables to positive integers:
6090  * - make all coefficients integral
6091  * - make all coefficients positive (substitute negated variable)
6092  */
6093  nconsvars = 0;
6094 
6095  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6096  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6097  */
6099  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6100  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6101 
6102  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6103  if( !success )
6104  intscalar = 1.0;
6105 
6106  /* make all coefficients integral and positive:
6107  * - scale a~_j = a_j * intscalar
6108  * - substitute x~_j = 1 - x_j if a~_j < 0
6109  */
6110  rhs = rhs * intscalar;
6111 
6112  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6113  minact = 0;
6114  maxact = 0;
6115  for( i = 0; i < nbinvars; i++ )
6116  {
6117  SCIP_VAR* var;
6118  SCIP_Longint val;
6119 
6120  val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6121  if( val == 0 )
6122  continue;
6123 
6124  if( val > 0 )
6125  {
6126  var = binvars[i];
6127  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6128  val, SCIPvarGetName(var), binvals[i], rhs);
6129  }
6130  else
6131  {
6132  assert(val < 0);
6133 
6134  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6135  val = -val; /*lint !e2704*/
6136  rhs += val;
6137  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6138  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6139  }
6140 
6141  if( SCIPvarGetLbLocal(var) > 0.5 )
6142  minact += val;
6143  if( SCIPvarGetUbLocal(var) > 0.5 )
6144  maxact += val;
6145  consvals[nconsvars] = val;
6146  consvars[nconsvars] = var;
6147  nconsvars++;
6148  }
6149 
6150  if( nconsvars > 0 )
6151  {
6152  SCIP_Longint capacity;
6153 
6154  assert(consvars != NULL);
6155  assert(consvals != NULL);
6156  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6157 
6158 #ifdef SCIP_DEBUG
6159  {
6160  SCIP_Real act;
6161 
6162  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6163  act = 0.0;
6164  for( i = 0; i < nconsvars; ++i )
6165  {
6166  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6167  SCIPgetSolVal(scip, sol, consvars[i]));
6168  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6169  }
6170  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6171  capacity, rhs, act, minact, maxact);
6172  }
6173 #endif
6174 
6175  if( minact > capacity )
6176  {
6177  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6178  *cutoff = TRUE;
6179  goto TERMINATE;
6180  }
6181 
6182  if( maxact > capacity )
6183  {
6184  /* separate lifted cut from relaxed knapsack constraint */
6185  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6186  }
6187  }
6188 
6189  TERMINATE:
6190  /* free data structures */
6191  if( noknapsackconshdlr)
6192  {
6193  SCIPfreeBufferArray(scip, &binvals);
6194  }
6195  else
6196  {
6197  /* clear binvals */
6198  for( --tmp; tmp >= 0; --tmp)
6199  {
6200  assert(tmpindices != NULL);
6201  binvals[tmpindices[tmp]] = 0;
6202  }
6203  SCIPfreeBufferArray(scip, &tmpindices);
6204  }
6205  SCIPfreeBufferArray(scip, &consvals);
6206  SCIPfreeBufferArray(scip, &consvars);
6207 
6208  return SCIP_OKAY;
6209 }
6210 
6211 /** separates given knapsack constraint */
6212 static
6214  SCIP* scip, /**< SCIP data structure */
6215  SCIP_CONS* cons, /**< knapsack constraint */
6216  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6217  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6218  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6219  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6220  int* ncuts /**< pointer to add up the number of found cuts */
6221  )
6222 {
6223  SCIP_CONSDATA* consdata;
6224  SCIP_Bool violated;
6225 
6226  assert(ncuts != NULL);
6227  assert(cutoff != NULL);
6228  *cutoff = FALSE;
6229 
6230  consdata = SCIPconsGetData(cons);
6231  assert(consdata != NULL);
6232 
6233  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6234 
6235  /* check knapsack constraint itself for feasibility */
6236  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6237 
6238  if( violated )
6239  {
6240  /* add knapsack constraint as LP row to the LP */
6241  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6242  (*ncuts)++;
6243  }
6244  else if( sepacuts )
6245  {
6246  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6247  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6248  }
6249 
6250  return SCIP_OKAY;
6251 }
6252 
6253 /** adds coefficient to constraint data */
6254 static
6256  SCIP* scip, /**< SCIP data structure */
6257  SCIP_CONS* cons, /**< knapsack constraint */
6258  SCIP_VAR* var, /**< variable to add to knapsack */
6259  SCIP_Longint weight /**< weight of variable in knapsack */
6260  )
6261 {
6262  SCIP_CONSDATA* consdata;
6264  consdata = SCIPconsGetData(cons);
6265  assert(consdata != NULL);
6266  assert(SCIPvarIsBinary(var));
6267  assert(weight > 0);
6268 
6269  /* add the new coefficient to the LP row */
6270  if( consdata->row != NULL )
6271  {
6272  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6273  }
6274 
6275  /* check for fixed variable */
6276  if( SCIPvarGetLbGlobal(var) > 0.5 )
6277  {
6278  /* variable is fixed to one: reduce capacity */
6279  consdata->capacity -= weight;
6280  }
6281  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6282  {
6283  SCIP_Bool negated;
6284 
6285  /* get binary representative of variable */
6286  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6287 
6288  /* insert coefficient */
6289  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6290  consdata->vars[consdata->nvars] = var;
6291  consdata->weights[consdata->nvars] = weight;
6292  consdata->nvars++;
6293 
6294  /* capture variable */
6295  SCIP_CALL( SCIPcaptureVar(scip, var) );
6296 
6297  /* install the rounding locks of variable */
6298  SCIP_CALL( lockRounding(scip, cons, var) );
6299 
6300  /* catch events */
6301  if( SCIPconsIsTransformed(cons) )
6302  {
6303  SCIP_CONSHDLRDATA* conshdlrdata;
6304 
6305  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6306  assert(conshdlrdata != NULL);
6307  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6309  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6310  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6311 
6312  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6313  consdata->existmultaggr = TRUE;
6314 
6315  /* mark constraint to be propagated and presolved */
6316  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6317  consdata->presolvedtiming = 0;
6318  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6319  }
6320 
6321  /* update weight sums */
6322  updateWeightSums(consdata, var, weight);
6323 
6324  consdata->sorted = FALSE;
6325  consdata->cliquepartitioned = FALSE;
6326  consdata->negcliquepartitioned = FALSE;
6327  consdata->merged = FALSE;
6328  }
6329 
6330  return SCIP_OKAY;
6331 }
6332 
6333 /** deletes coefficient at given position from constraint data */
6334 static
6336  SCIP* scip, /**< SCIP data structure */
6337  SCIP_CONS* cons, /**< knapsack constraint */
6338  int pos /**< position of coefficient to delete */
6339  )
6340 {
6341  SCIP_CONSDATA* consdata;
6342  SCIP_VAR* var;
6344  consdata = SCIPconsGetData(cons);
6345  assert(consdata != NULL);
6346  assert(0 <= pos && pos < consdata->nvars);
6347 
6348  var = consdata->vars[pos];
6349  assert(var != NULL);
6350  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6351 
6352  /* delete the coefficient from the LP row */
6353  if( consdata->row != NULL )
6354  {
6355  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6356  }
6357 
6358  /* remove the rounding locks of variable */
6359  SCIP_CALL( unlockRounding(scip, cons, var) );
6360 
6361  /* drop events and mark constraint to be propagated and presolved */
6362  if( SCIPconsIsTransformed(cons) )
6363  {
6364  SCIP_CONSHDLRDATA* conshdlrdata;
6365 
6366  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6367  assert(conshdlrdata != NULL);
6369  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6370  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6371 
6372  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6373  consdata->presolvedtiming = 0;
6374  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6375  }
6376 
6377  /* decrease weight sums */
6378  updateWeightSums(consdata, var, -consdata->weights[pos]);
6379 
6380  /* move the last variable to the free slot */
6381  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6382  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6383  if( consdata->eventdata != NULL )
6384  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6385 
6386  /* release variable */
6387  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6388 
6389  /* try to use old clique partitions */
6390  if( consdata->cliquepartitioned )
6391  {
6392  assert(consdata->cliquepartition != NULL);
6393  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6394  * change the clique number */
6395  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6396  {
6397  int oldcliqenum;
6398 
6399  oldcliqenum = consdata->cliquepartition[pos];
6400  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6401 
6402  /* the following if and else cases assure that we have increasing clique numbers */
6403  if( consdata->cliquepartition[pos] > pos )
6404  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6405  else
6406  {
6407  int i;
6408  int cliquenumbefore;
6409 
6410  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6411  * occurs the same as the old one is still in the cliquepartition */
6412  if( oldcliqenum > consdata->cliquepartition[pos] )
6413  {
6414  for( i = 0; i < consdata->nvars; ++i )
6415  if( oldcliqenum == consdata->cliquepartition[i] )
6416  break;
6417  else if( oldcliqenum < consdata->cliquepartition[i] )
6418  {
6419  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6420  break;
6421  }
6422  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6423  * the biggest index, so decrease the number of cliques
6424  */
6425  if( i == consdata->nvars )
6426  --(consdata->ncliques);
6427  }
6428  /* if the old clique number was smaller than the new one we have to check the front for an element with
6429  * clique number minus 1 */
6430  else if( oldcliqenum < consdata->cliquepartition[pos] )
6431  {
6432  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6433  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6434 
6435  if( i < cliquenumbefore )
6436  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6437  }
6438  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6439  else if( pos == consdata->nvars - 1)
6440  {
6441  cliquenumbefore = consdata->cliquepartition[pos];
6442  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6443 
6444  if( i < cliquenumbefore )
6445  --(consdata->ncliques);
6446  }
6447  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6448  }
6449  }
6450  else
6451  --(consdata->ncliques);
6452  }
6453 
6454  if( consdata->negcliquepartitioned )
6455  {
6456  assert(consdata->negcliquepartition != NULL);
6457  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6458  * change the clique number */
6459  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6460  {
6461  int oldcliqenum;
6462 
6463  oldcliqenum = consdata->negcliquepartition[pos];
6464  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6465 
6466  /* the following if and else cases assure that we have increasing clique numbers */
6467  if( consdata->negcliquepartition[pos] > pos )
6468  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6469  else
6470  {
6471  int i;
6472  int cliquenumbefore;
6473 
6474  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6475  * occurs, the same as the old one occurs */
6476  if( oldcliqenum > consdata->negcliquepartition[pos] )
6477  {
6478  for( i = 0; i < consdata->nvars; ++i )
6479  if( oldcliqenum == consdata->negcliquepartition[i] )
6480  break;
6481  else if( oldcliqenum < consdata->negcliquepartition[i] )
6482  {
6483  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6484  break;
6485  }
6486  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6487  * the biggest index, so decrease the number of negated cliques
6488  */
6489  if( i == consdata->nvars )
6490  --(consdata->nnegcliques);
6491  }
6492  /* if the old clique number was smaller than the new one we have to check the front for an element with
6493  * clique number minus 1 */
6494  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6495  {
6496  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6497  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6498 
6499  if( i < cliquenumbefore )
6500  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6501  }
6502  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6503  else if( pos == consdata->nvars - 1)
6504  {
6505  cliquenumbefore = consdata->negcliquepartition[pos];
6506  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6507 
6508  if( i < cliquenumbefore )
6509  --(consdata->nnegcliques);
6510  }
6511  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6512  }
6513  }
6514  else
6515  --(consdata->nnegcliques);
6516  }
6517 
6518  --(consdata->nvars);
6519 
6520  return SCIP_OKAY;
6521 }
6522 
6523 /** removes all items with weight zero from knapsack constraint */
6524 static
6526  SCIP* scip, /**< SCIP data structure */
6527  SCIP_CONS* cons /**< knapsack constraint */
6528  )
6529 {
6530  SCIP_CONSDATA* consdata;
6531  int v;
6532 
6533  consdata = SCIPconsGetData(cons);
6534  assert(consdata != NULL);
6535 
6536  for( v = consdata->nvars-1; v >= 0; --v )
6537  {
6538  if( consdata->weights[v] == 0 )
6539  {
6540  SCIP_CALL( delCoefPos(scip, cons, v) );
6541  }
6542  }
6543 
6544  return SCIP_OKAY;
6545 }
6546 
6547 /* perform deletion of variables in all constraints of the constraint handler */
6548 static
6550  SCIP* scip, /**< SCIP data structure */
6551  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6552  SCIP_CONS** conss, /**< array of constraints */
6553  int nconss /**< number of constraints */
6554  )
6555 {
6556  SCIP_CONSDATA* consdata;
6557  int i;
6558  int v;
6559 
6560  assert(scip != NULL);
6561  assert(conshdlr != NULL);
6562  assert(conss != NULL);
6563  assert(nconss >= 0);
6564  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6565 
6566  /* iterate over all constraints */
6567  for( i = 0; i < nconss; i++ )
6568  {
6569  consdata = SCIPconsGetData(conss[i]);
6570 
6571  /* constraint is marked, that some of its variables were deleted */
6572  if( consdata->varsdeleted )
6573  {
6574  /* iterate over all variables of the constraint and delete them from the constraint */
6575  for( v = consdata->nvars - 1; v >= 0; --v )
6576  {
6577  if( SCIPvarIsDeleted(consdata->vars[v]) )
6578  {
6579  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6580  }
6581  }
6582  consdata->varsdeleted = FALSE;
6583  }
6584  }
6585 
6586  return SCIP_OKAY;
6587 }
6588 
6589 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6590 static
6592  SCIP* scip, /**< SCIP data structure */
6593  SCIP_CONS* cons, /**< knapsack constraint */
6594  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6595  )
6596 {
6597  SCIP_CONSDATA* consdata;
6598  int v;
6599  int prev;
6600 
6601  assert(scip != NULL);
6602  assert(cons != NULL);
6603  assert(cutoff != NULL);
6604 
6605  consdata = SCIPconsGetData(cons);
6606  assert(consdata != NULL);
6607 
6608  *cutoff = FALSE;
6609 
6610  if( consdata->merged )
6611  return SCIP_OKAY;
6612 
6613  if( consdata->nvars <= 1 )
6614  {
6615  consdata->merged = TRUE;
6616  return SCIP_OKAY;
6617  }
6618 
6619  assert(consdata->vars != NULL || consdata->nvars == 0);
6620 
6621  /* sorting array after indices of variables, that's only for faster merging */
6622  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6623  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6624 
6625  /* knapsack-sorting (decreasing weights) now lost */
6626  consdata->sorted = FALSE;
6627 
6628  v = consdata->nvars - 1;
6629  prev = v - 1;
6630  /* loop backwards through the items: deletion only affects rear items */
6631  while( prev >= 0 )
6632  {
6633  SCIP_VAR* var1;
6634  SCIP_VAR* var2;
6635  SCIP_Bool negated1;
6636  SCIP_Bool negated2;
6637 
6638  negated1 = FALSE;
6639  negated2 = FALSE;
6640 
6641  var1 = consdata->vars[v];
6642  assert(SCIPvarIsBinary(var1));
6643  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6645  {
6646  var1 = SCIPvarGetNegatedVar(var1);
6647  negated1 = TRUE;
6648  }
6649  assert(var1 != NULL);
6650 
6651  var2 = consdata->vars[prev];
6652  assert(SCIPvarIsBinary(var2));
6653  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6655  {
6656  var2 = SCIPvarGetNegatedVar(var2);
6657  negated2 = TRUE;
6658  }
6659  assert(var2 != NULL);
6660 
6661  if( var1 == var2 )
6662  {
6663  /* both variables are either active or negated */
6664  if( negated1 == negated2 )
6665  {
6666  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6667  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6668  SCIP_CALL( delCoefPos(scip, cons, v) );
6669  }
6670  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6671  * and delete item of smaller weight
6672  */
6673  else if( consdata->weights[v] == consdata->weights[prev] )
6674  {
6675  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6676  consdata->capacity -= consdata->weights[v];
6677  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6678  SCIP_CALL( delCoefPos(scip, cons, prev) );
6679 
6680  --prev;
6681  }
6682  else if( consdata->weights[v] < consdata->weights[prev] )
6683  {
6684  consdata->capacity -= consdata->weights[v];
6685  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6686  assert(consdata->weights[prev] > 0);
6687  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6688  }
6689  else
6690  {
6691  consdata->capacity -= consdata->weights[prev];
6692  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6693  assert(consdata->weights[v] > 0);
6694  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6695  /* restore order iff necessary */
6696  if( consdata->nvars != v ) /* otherwise the order still stands */
6697  {
6698  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6699  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6700  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6701  --prev;
6702  else /* we need to let v at the same position*/
6703  {
6704  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6705  /* don't decrease v, the same variable may exist up front */
6706  --prev;
6707  continue;
6708  }
6709  }
6710  }
6711  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6712  }
6713  v = prev;
6714  --prev;
6715  }
6716 
6717  consdata->merged = TRUE;
6718 
6719  /* check infeasibility */
6720  if( consdata->onesweightsum > consdata->capacity )
6721  {
6722  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6723  *cutoff = TRUE;
6724  return SCIP_OKAY;
6725  }
6726 
6727  return SCIP_OKAY;
6728 }
6729 
6730 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6731  * fixings (dual reductions)
6732  */
6733 static
6735  SCIP* scip, /**< SCIP data structure */
6736  SCIP_CONS* cons, /**< knapsack constraint */
6737  int* nfixedvars, /**< pointer to count number of fixings */
6738  int* ndelconss, /**< pointer to count number of deleted constraints */
6739  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6740  )
6741 {
6742  SCIP_CONSDATA* consdata;
6743  SCIP_VAR** vars;
6744  SCIP_Real* profits;
6745  int* solitems;
6746  int* nonsolitems;
6747  int* items;
6748  SCIP_Real solval;
6749  SCIP_Bool infeasible;
6750  SCIP_Bool tightened;
6751  SCIP_Bool applicable;
6752  int nsolitems;
6753  int nnonsolitems;
6754  int nvars;
6755  int v;
6756 
6757  assert(!SCIPconsIsModifiable(cons));
6758 
6759  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6760  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6761  * added to the problems have the check flag set to FALSE
6762  */
6763  if( !SCIPconsIsChecked(cons) )
6764  return SCIP_OKAY;
6765 
6766  consdata = SCIPconsGetData(cons);
6767  assert(consdata != NULL);
6768 
6769  nvars = consdata->nvars;
6770  vars = consdata->vars;
6771 
6772  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6773  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6774  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6775  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6776 
6777  applicable = TRUE;
6778 
6779  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6780  * collect object values which are the profits of the knapsack problem
6781  */
6782  for( v = 0; v < nvars; ++v )
6783  {
6784  SCIP_VAR* var;
6785  SCIP_Bool negated;
6786 
6787  var = vars[v];
6788  assert(var != NULL);
6789 
6790  /* the variable should not be (globally) fixed */
6791  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6792 
6795  {
6796  applicable = FALSE;
6797  break;
6798  }
6799 
6800  negated = FALSE;
6801 
6802  /* get the active variable */
6803  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6804  assert(SCIPvarIsActive(var));
6805 
6806  if( negated )
6807  profits[v] = SCIPvarGetObj(var);
6808  else
6809  profits[v] = -SCIPvarGetObj(var);
6810 
6811  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6812  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6813  items[v] = v;
6814  }
6815 
6816  if( applicable )
6817  {
6818  SCIP_Bool success;
6819 
6820  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6821  SCIPdebugPrintCons(scip, cons, NULL);
6822 
6823  /* solve knapsack problem exactly */
6824  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6825  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6826 
6827  if( success )
6828  {
6829  SCIP_VAR* var;
6830 
6831  /* apply solution of the knapsack as dual reductions */
6832  for( v = 0; v < nsolitems; ++v )
6833  {
6834  var = vars[solitems[v]];
6835  assert(var != NULL);
6836 
6837  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6839  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6840  assert(!infeasible);
6841  assert(tightened);
6842  (*nfixedvars)++;
6843  }
6844 
6845  for( v = 0; v < nnonsolitems; ++v )
6846  {
6847  var = vars[nonsolitems[v]];
6848  assert(var != NULL);
6849 
6850  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6852  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6853  assert(!infeasible);
6854  assert(tightened);
6855  (*nfixedvars)++;
6856  }
6857 
6858  SCIP_CALL( SCIPdelCons(scip, cons) );
6859  (*ndelconss)++;
6860  (*deleted) = TRUE;
6861  }
6862  }
6863 
6864  SCIPfreeBufferArray(scip, &nonsolitems);
6865  SCIPfreeBufferArray(scip, &solitems);
6866  SCIPfreeBufferArray(scip, &items);
6867  SCIPfreeBufferArray(scip, &profits);
6868 
6869  return SCIP_OKAY;
6870 }
6871 
6872 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6873  * constraint enters the LP by setting the initial and separated flag to FALSE
6874  */
6875 static
6877  SCIP* scip, /**< SCIP data structure */
6878  SCIP_CONS* cons, /**< knapsack constraint */
6879  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6880  )
6881 {
6882  SCIP_CONSDATA* consdata;
6883  SCIP_VAR** vars;
6884  SCIP_VAR* var;
6885  SCIP_Real offset;
6886  SCIP_Real scale;
6887  SCIP_Real objval;
6888  SCIP_Bool applicable;
6889  SCIP_Bool negated;
6890  int nobjvars;
6891  int nvars;
6892  int v;
6893 
6894  assert(scip != NULL);
6895  assert(cons != NULL);
6896  assert(conshdlrdata != NULL);
6897 
6898  consdata = SCIPconsGetData(cons);
6899  assert(consdata != NULL);
6900 
6901  nvars = consdata->nvars;
6902  nobjvars = SCIPgetNObjVars(scip);
6903 
6904  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6905  * and/or separated flag is set to FALSE
6906  */
6907  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6908  return SCIP_OKAY;
6909 
6910  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6911  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6912  */
6913  if( nobjvars == 0 )
6914  return SCIP_OKAY;
6915 
6916  vars = consdata->vars;
6917  assert(vars != NULL);
6918 
6919  applicable = TRUE;
6920  offset = 0.0;
6921  scale = 1.0;
6922 
6923  for( v = 0; v < nvars && applicable; ++v )
6924  {
6925  negated = FALSE;
6926  var = vars[v];
6927  assert(var != NULL);
6928 
6929  if( SCIPvarIsNegated(var) )
6930  {
6931  negated = TRUE;
6932  var = SCIPvarGetNegatedVar(var);
6933  assert(var != NULL);
6934  }
6935 
6936  objval = SCIPvarGetObj(var);
6937 
6938  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6939  if( SCIPisZero(scip, objval) )
6940  applicable = FALSE;
6941  else
6942  {
6943  SCIP_Real weight;
6944 
6945  weight = (SCIP_Real)consdata->weights[v];
6946 
6947  if( negated )
6948  {
6949  if( v == 0 )
6950  {
6951  /* the first variable defines the scale */
6952  scale = weight / -objval;
6953 
6954  offset += weight;
6955  }
6956  else if( SCIPisEQ(scip, -objval * scale, weight) )
6957  offset += weight;
6958  else
6959  applicable = FALSE;
6960  }
6961  else if( v == 0 )
6962  {
6963  /* the first variable define the scale */
6964  scale = weight / objval;
6965  }
6966  else if( !SCIPisEQ(scip, objval * scale, weight) )
6967  applicable = FALSE;
6968  }
6969  }
6970 
6971  if( applicable )
6972  {
6973  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6974  {
6975  SCIP_Real cutoffbound;
6976 
6977  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6978  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6979  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6980 
6981  cutoffbound = (consdata->capacity - offset) / scale;
6982 
6983  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6984  SCIPconsGetName(cons), cutoffbound);
6985 
6986  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6987  * still excepted
6988  */
6989  cutoffbound += SCIPcutoffbounddelta(scip);
6990 
6991  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6992  SCIPconsGetName(cons), cutoffbound);
6993 
6994  if( cutoffbound < SCIPgetCutoffbound(scip) )
6995  {
6996  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6997 
6998  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6999  }
7000  else
7001  {
7002  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7003  * propagation
7004  */
7005  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
7006  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
7007  }
7008  }
7009  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7010  {
7011  SCIP_Real lowerbound;
7012 
7013  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7014  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
7015  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
7016 
7017  lowerbound = (consdata->capacity - offset) / scale;
7018 
7019  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7020  SCIPconsGetName(cons), lowerbound);
7021 
7022  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
7023  }
7024  }
7025 
7026  return SCIP_OKAY;
7027 }
7028 
7029 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7030  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7031 static
7033  SCIP* scip, /**< SCIP data structure */
7034  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7035  SCIP_VAR** vars, /**< array for sorted variables */
7036  SCIP_Longint* weights, /**< array for sorted weights */
7037  int* cliquestartposs, /**< starting position array for each clique */
7038  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7039  )
7040 {
7041  SCIP_VAR** origvars;
7042  int norigvars;
7043  SCIP_Longint* origweights;
7044  int* cliquepartition;
7045  int ncliques;
7046 
7047  SCIP_VAR*** varpointers;
7048  SCIP_Longint** weightpointers;
7049  int* cliquecount;
7050 
7051  int nextpos;
7052  int c;
7053  int v;
7054 
7055  assert(scip != NULL);
7056  assert(consdata != NULL);
7057  assert(vars != NULL);
7058  assert(weights != NULL);
7059  assert(cliquestartposs != NULL);
7060 
7061  origweights = consdata->weights;
7062  origvars = consdata->vars;
7063  norigvars = consdata->nvars;
7064 
7065  assert(origvars != NULL || norigvars == 0);
7066  assert(origweights != NULL || norigvars == 0);
7067 
7068  if( norigvars == 0 )
7069  return SCIP_OKAY;
7070 
7071  if( usenegatedclique )
7072  {
7073  assert(consdata->negcliquepartitioned);
7074 
7075  cliquepartition = consdata->negcliquepartition;
7076  ncliques = consdata->nnegcliques;
7077  }
7078  else
7079  {
7080  assert(consdata->cliquepartitioned);
7081 
7082  cliquepartition = consdata->cliquepartition;
7083  ncliques = consdata->ncliques;
7084  }
7085 
7086  assert(cliquepartition != NULL);
7087  assert(ncliques > 0);
7088 
7089  /* we first count all clique items and alloc temporary memory for a bucket sort */
7090  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7091  BMSclearMemoryArray(cliquecount, ncliques);
7092 
7093  /* first we count for each clique the number of elements */
7094  for( v = norigvars - 1; v >= 0; --v )
7095  {
7096  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7097  ++(cliquecount[cliquepartition[v]]);
7098  }
7099 
7100  /*@todo: maybe it is better to put largest cliques up front */
7101 
7102 #ifndef NDEBUG
7103  BMSclearMemoryArray(vars, norigvars);
7104  BMSclearMemoryArray(weights, norigvars);
7105 #endif
7106  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7107  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7108 
7109  nextpos = 0;
7110  /* now we initialize all start pointers for each clique, so they will be ordered */
7111  for( c = 0; c < ncliques; ++c )
7112  {
7113  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7114  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7115  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7116  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7117  * vars[7]
7118  *
7119  */
7120  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7121  cliquestartposs[c] = nextpos;
7122  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7123  assert(cliquecount[c] > 0);
7124  nextpos += cliquecount[c];
7125  assert(nextpos > 0);
7126  }
7127  assert(nextpos == norigvars);
7128  cliquestartposs[c] = nextpos;
7129 
7130  /* now we copy all variable and weights to the right order */
7131  for( v = 0; v < norigvars; ++v )
7132  {
7133  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7134  ++(varpointers[cliquepartition[v]]);
7135  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7136  ++(weightpointers[cliquepartition[v]]);
7137  }
7138 #ifndef NDEBUG
7139  for( v = 0; v < norigvars; ++v )
7140  {
7141  assert(vars[v] != NULL);
7142  assert(weights[v] > 0);
7143  }
7144 #endif
7145 
7146  /* free temporary memory */
7147  SCIPfreeBufferArray(scip, &weightpointers);
7148  SCIPfreeBufferArray(scip, &varpointers);
7149  SCIPfreeBufferArray(scip, &cliquecount);
7150 
7151  return SCIP_OKAY;
7152 }
7153 
7154 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7155 static
7157  SCIP* scip, /**< SCIP data structure */
7158  SCIP_CONS* cons, /**< knapsack constraint */
7159  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7160  * information is not needed; in this case, we apply all fixings
7161  * instead of stopping after the first infeasible one */
7162  )
7163 {
7164  SCIP_CONSDATA* consdata;
7165  int v;
7166 
7167  assert(scip != NULL);
7168  assert(cons != NULL);
7169 
7170  consdata = SCIPconsGetData(cons);
7171  assert(consdata != NULL);
7172  assert(consdata->nvars == 0 || consdata->vars != NULL);
7173 
7174  if( cutoff != NULL )
7175  *cutoff = FALSE;
7176 
7177  SCIPdebugMsg(scip, "apply fixings:\n");
7178  SCIPdebugPrintCons(scip, cons, NULL);
7179 
7180  /* check infeasibility */
7181  if ( consdata->onesweightsum > consdata->capacity )
7182  {
7183  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7184 
7185  if( cutoff != NULL )
7186  *cutoff = TRUE;
7187 
7188  return SCIP_OKAY;
7189  }
7190 
7191  /* all multi-aggregations should be resolved */
7192  consdata->existmultaggr = FALSE;
7193 
7194  v = 0;
7195  while( v < consdata->nvars )
7196  {
7197  SCIP_VAR* var;
7198 
7199  var = consdata->vars[v];
7200  assert(SCIPvarIsBinary(var));
7201 
7202  if( SCIPvarGetLbGlobal(var) > 0.5 )
7203  {
7204  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7205  consdata->capacity -= consdata->weights[v];
7206  SCIP_CALL( delCoefPos(scip, cons, v) );
7207  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7208  }
7209  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7210  {
7211  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7212  SCIP_CALL( delCoefPos(scip, cons, v) );
7213  }
7214  else
7215  {
7216  SCIP_VAR* repvar;
7217  SCIP_VAR* negvar;
7218  SCIP_VAR* workvar;
7219  SCIP_Longint weight;
7220  SCIP_Bool negated;
7221 
7222  weight = consdata->weights[v];
7223 
7224  /* get binary representative of variable */
7225  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7226  assert(repvar != NULL);
7227 
7228  /* check for multi-aggregation */
7229  if( SCIPvarIsNegated(repvar) )
7230  {
7231  workvar = SCIPvarGetNegatedVar(repvar);
7232  assert(workvar != NULL);
7233  negated = TRUE;
7234  }
7235  else
7236  {
7237  workvar = repvar;
7238  negated = FALSE;
7239  }
7240 
7241  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7242  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7243  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7244  *
7245  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7246  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7247  *
7248  * The explanation for the following block:
7249  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7250  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7251  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7252  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7253  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7254  * 2) For all replacement variable we check:
7255  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7256  * capacity -= weight * a_i caused by the negation of y_i.
7257  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7258  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7259  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7260  * weight in this case.
7261  */
7262  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7263  {
7264  SCIP_VAR** aggrvars;
7265  SCIP_Real* aggrscalars;
7266  SCIP_Real aggrconst;
7267  int naggrvars;
7268  int i;
7269 
7270  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7271  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7272  aggrvars = SCIPvarGetMultaggrVars(workvar);
7273  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7274  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7275  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7276 
7277  if( !SCIPisIntegral(scip, weight * aggrconst) )
7278  {
7279  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7280  return SCIP_ERROR;
7281  }
7282 
7283  /* if workvar was negated, we have to flip the weight */
7284  if( negated )
7285  weight *= -1;
7286 
7287  for( i = naggrvars - 1; i >= 0; --i )
7288  {
7289  assert(aggrvars != NULL);
7290  assert(aggrscalars != NULL);
7291 
7292  if( !SCIPvarIsBinary(aggrvars[i]) )
7293  {
7294  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7295  SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7296  return SCIP_ERROR;
7297  }
7298  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7299  {
7300  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7301  return SCIP_ERROR;
7302  }
7303  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7304  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7305  {
7306  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7307  assert(negvar != NULL);
7308  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7309  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7310  }
7311  else
7312  {
7313  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7314  }
7315  }
7316  /* delete old coefficient */
7317  SCIP_CALL( delCoefPos(scip, cons, v) );
7318 
7319  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7320  if( negated )
7321  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7322  else
7323  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7324 
7325  if( consdata->capacity < 0 )
7326  {
7327  if( cutoff != NULL )
7328  {
7329  *cutoff = TRUE;
7330  break;
7331  }
7332  }
7333  }
7334  /* check, if the variable should be replaced with the representative */
7335  else if( repvar != var )
7336  {
7337  /* delete old (aggregated) variable */
7338  SCIP_CALL( delCoefPos(scip, cons, v) );
7339 
7340  /* add representative instead */
7341  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7342  }
7343  else
7344  ++v;
7345  }
7346  }
7347  assert(consdata->onesweightsum == 0);
7348 
7349  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7350  SCIPdebugPrintCons(scip, cons, NULL);
7351 
7352  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7353  * clean up the constraint
7354  */
7355  if( cutoff != NULL && !(*cutoff) )
7356  {
7357  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7358  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7359  SCIPdebugPrintCons(scip, cons, NULL);
7360  }
7361 
7362  return SCIP_OKAY;
7363 }
7364 
7365 
7366 /** propagation method for knapsack constraints */
7367 static
7369  SCIP* scip, /**< SCIP data structure */
7370  SCIP_CONS* cons, /**< knapsack constraint */
7371  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7372  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7373  int* nfixedvars, /**< pointer to count number of fixings */
7374  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7375  )
7377  SCIP_CONSDATA* consdata;
7378  SCIP_Bool infeasible;
7379  SCIP_Bool tightened;
7380  SCIP_Longint* secondmaxweights;
7381  SCIP_Longint minweightsum;
7382  SCIP_Longint residualcapacity;
7383 
7384  int nvars;
7385  int i;
7386  int nnegcliques;
7387 
7388  SCIP_VAR** myvars;
7389  SCIP_Longint* myweights;
7390  int* cliquestartposs;
7391  int* cliqueendposs;
7392  SCIP_Longint localminweightsum;
7393  SCIP_Bool foundmax;
7394  int c;
7395 
7396  assert(scip != NULL);
7397  assert(cons != NULL);
7398  assert(cutoff != NULL);
7399  assert(redundant != NULL);
7400  assert(nfixedvars != NULL);
7401 
7402  consdata = SCIPconsGetData(cons);
7403  assert(consdata != NULL);
7404 
7405  *cutoff = FALSE;
7406  *redundant = FALSE;
7407 
7408  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7409 
7410  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7411  if( !SCIPinRepropagation(scip) )
7412  {
7413  SCIP_CALL( SCIPincConsAge(scip, cons) );
7414  }
7415 
7416 #ifndef NDEBUG
7417  /* assert that only active or negated variables are present */
7418  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7419  {
7420  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7421  }
7422 #endif
7423 
7424  usenegatedclique = usenegatedclique && consdata->merged;
7425 
7426  /* init for debugging */
7427  myvars = NULL;
7428  myweights = NULL;
7429  cliquestartposs = NULL;
7430  secondmaxweights = NULL;
7431  minweightsum = 0;
7432  nvars = consdata->nvars;
7433  /* make sure, the items are sorted by non-increasing weight */
7434  sortItems(consdata);
7435 
7436  do
7437  {
7438  localminweightsum = 0;
7439 
7440  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7441  * a negated clique means, that at most one of the clique variables can be zero
7442  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7443  *
7444  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7445  * since replacing i with the element of maximal weight leads to infeasibility
7446  */
7447  if( usenegatedclique && nvars > 0 )
7448  {
7449  SCIP_CONSHDLRDATA* conshdlrdata;
7450  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7451  assert(conshdlrdata != NULL);
7452 
7453  /* compute clique partitions */
7454  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7455  nnegcliques = consdata->nnegcliques;
7456 
7457  /* if we have no real negated cliques we can stop here */
7458  if( nnegcliques == nvars )
7459  {
7460  /* run the standard algorithm that does not involve cliques */
7461  usenegatedclique = FALSE;
7462  break;
7463  }
7464 
7465  /* allocate temporary memory and initialize it */
7466  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7467  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7468  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7469  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7470  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7471  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7472 
7473  /* resort variables to avoid quadratic algorithm later on */
7474  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7475 
7476  /* save the end positions of the cliques because start positions are moved in the following loop */
7477  for( c = 0; c < nnegcliques; ++c )
7478  {
7479  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7480  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7481  }
7482 
7483  c = 0;
7484  foundmax = FALSE;
7485  i = 0;
7486 
7487  while( i < nvars )
7488  {
7489  /* ignore variables of the negated clique which are fixed to one since these are counted in
7490  * consdata->onesweightsum
7491  */
7492 
7493  /* if there are only one variable negated cliques left we can stop */
7494  if( nnegcliques - c == nvars - i )
7495  {
7496  minweightsum += localminweightsum;
7497  localminweightsum = 0;
7498  break;
7499  }
7500 
7501  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7502  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7503  * other clique variables to one
7504  */
7505  if( cliquestartposs[c] == i )
7506  {
7507  assert(myweights[i] > 0);
7508  ++c;
7509  minweightsum += localminweightsum;
7510  localminweightsum = 0;
7511  foundmax = TRUE;
7512 
7513  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7514  foundmax = FALSE;
7515 
7516  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7517  {
7518  ++i;
7519  continue;
7520  }
7521  }
7522 
7523  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7524  {
7525  assert(myweights[i] > 0);
7526 
7527  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7528  {
7529  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7530 
7531  if( !foundmax )
7532  {
7533  foundmax = TRUE;
7534 
7535  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7536  cliquestartposs[c - 1] = i;
7537  ++i;
7538 
7539  continue;
7540  }
7541  /* memorize second max weight for each clique */
7542  if( secondmaxweights[c - 1] == 0 )
7543  secondmaxweights[c - 1] = myweights[i];
7544 
7545  localminweightsum += myweights[i];
7546  }
7547  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7548  else
7549  {
7550  int v;
7551  /* fix all other variables of the negated clique to 1 */
7552  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7553  {
7554  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7555  {
7556  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7557  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7558 
7559  if( infeasible )
7560  {
7561  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7562 
7563  /* analyze the infeasibility if conflict analysis is applicable */
7565  {
7566  /* conflict analysis can only be applied in solving stage */
7567  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7568 
7569  /* initialize the conflict analysis */
7571 
7572  /* add the two variables which are fixed to zero within a negated clique */
7573  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7574  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7575 
7576  /* start the conflict analysis */
7577  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7578  }
7579  *cutoff = TRUE;
7580  break;
7581  }
7582  assert(tightened);
7583  ++(*nfixedvars);
7584  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7585  }
7586  }
7587 
7588  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7589  localminweightsum = 0;
7590  /* we can jump to the end of this clique */
7591  i = cliqueendposs[c - 1];
7592 
7593  if( *cutoff )
7594  break;
7595  }
7596  }
7597  ++i;
7598  }
7599  /* add last clique minweightsum */
7600  minweightsum += localminweightsum;
7601 
7602  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7603  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7604 
7605  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7606  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7607  {
7608  SCIP_Longint maxcliqueweight = -1LL;
7609 
7610  /* loop over cliques */
7611  for( c = 0; c < nnegcliques; ++c )
7612  {
7613  SCIP_VAR* maxvar;
7614  SCIP_Bool maxvarfixed;
7615  int endvarposclique;
7616  int startvarposclique;
7617 
7618  assert(myvars != NULL);
7619  assert(nnegcliques == consdata->nnegcliques);
7620  assert(myweights != NULL);
7621  assert(secondmaxweights != NULL);
7622  assert(cliquestartposs != NULL);
7623 
7624  endvarposclique = cliqueendposs[c];
7625  startvarposclique = cliquestartposs[c];
7626 
7627  maxvar = myvars[startvarposclique];
7628 
7629  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7630  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7631  continue;
7632 
7633  maxcliqueweight = myweights[startvarposclique];
7634  maxvarfixed = FALSE;
7635  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7636  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7637  * exceeds the capacity the maximum weight variable can be fixed to zero.
7638  */
7639  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7640  {
7641 #ifndef NDEBUG
7642  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7643 #endif
7644  assert(maxcliqueweight >= secondmaxweights[c]);
7645  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7646 
7647  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7648  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7649  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7650  assert(consdata->onesweightsum == oldonesweightsum);
7651  assert(!infeasible);
7652  assert(tightened);
7653  (*nfixedvars)++;
7654  maxvarfixed = TRUE;
7655  }
7656  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7657  * fits into the knapsack
7658  */
7659  else if( nnegcliques - c == nvars - startvarposclique )
7660  break;
7661  /* early termination of the remaining loop because no further variable fixings are possible:
7662  *
7663  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7664  * largest was set to 0) does not suffice to infer additional variable fixings because
7665  *
7666  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7667  * - their second largest elements are at least as large as the smallest weight of the knapsack
7668  */
7669  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7670  break;
7671 
7672  /* loop over items with non-maximal weight (omitting the first position) */
7673  for( i = endvarposclique; i > startvarposclique; --i )
7674  {
7675  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7676  * messed up the clique preprocessing in the previous loop to filter those variables out */
7677  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7678 
7679  /* only check variables of negated cliques for which no variable is locally fixed */
7680  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7681  {
7682  assert(maxcliqueweight >= myweights[i]);
7683  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7684 
7685  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7686  *
7687  * the maxvar was already fixed to 0 because it has a huge gain.
7688  *
7689  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7690  * since replacing i with the element of maximal weight leads to infeasibility */
7691  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7692  {
7693 #ifndef NDEBUG
7694  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7695 #endif
7696  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7697  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7698  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7699  assert(!infeasible);
7700  assert(tightened);
7701  ++(*nfixedvars);
7702  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7703 
7704  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7705  * consdata->onesweightsum
7706  */
7707  minweightsum -= myweights[i];
7708  assert(minweightsum >= 0);
7709  }
7710  else
7711  break;
7712  }
7713  }
7714 #ifndef NDEBUG
7715  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7716  for( ; i > startvarposclique; --i )
7717  {
7718  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7719  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7720 
7721  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7722  assert(varisfixed || !exceedscapacity);
7723  }
7724 #endif
7725  }
7726  }
7727  SCIPfreeBufferArray(scip, &secondmaxweights);
7728  SCIPfreeBufferArray(scip, &cliqueendposs);
7729  SCIPfreeBufferArray(scip, &cliquestartposs);
7730  SCIPfreeBufferArray(scip, &myweights);
7731  SCIPfreeBufferArray(scip, &myvars);
7732  }
7733 
7734  assert(consdata->negcliquepartitioned || minweightsum == 0);
7735  }
7736  while( FALSE );
7737 
7738  assert(usenegatedclique || minweightsum == 0);
7739  /* check, if weights of fixed variables already exceed knapsack capacity */
7740  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7741  {
7742  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7743  consdata->onesweightsum, consdata->capacity);
7744 
7745  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7746  *cutoff = TRUE;
7747 
7748  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7750  {
7751  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7752  SCIP_Longint weight;
7753 
7754  weight = 0;
7755 
7757 
7758  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7759  {
7760  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7761  {
7762  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7763  weight += consdata->weights[i];
7764  }
7765  }
7766 
7767  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7768  }
7769 
7770  return SCIP_OKAY;
7771  }
7772 
7773  /* the algorithm below is a special case of propagation involving negated cliques */
7774  if( !usenegatedclique )
7775  {
7776  assert(consdata->sorted);
7777  residualcapacity = consdata->capacity - consdata->onesweightsum;
7778 
7779  /* fix all variables to zero, that don't fit into the knapsack anymore */
7780  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7781  {
7782  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7783  * to zero
7784  */
7785  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7786  {
7787  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7788  {
7789  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7790  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7791  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7792  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7793  assert(!infeasible);
7794  assert(tightened);
7795  (*nfixedvars)++;
7796  }
7797  }
7798  }
7799  }
7800 
7801  /* check if the knapsack is now redundant */
7802  if( !SCIPconsIsModifiable(cons) )
7803  {
7804  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7805 
7806  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7807  for( i = 0; i < nvars; ++i )
7808  {
7809  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7810  {
7811  unfixedweightsum += consdata->weights[i];
7812 
7813  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7814  if( unfixedweightsum > consdata->capacity )
7815  return SCIP_OKAY;
7816  }
7817  }
7818  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7819  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7820  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7821  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7822  *redundant = TRUE;
7823  }
7824 
7825  return SCIP_OKAY;
7826 }
7827 
7828 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7829  * containing all negated variables of this knapsack constraint
7830  */
7831 static
7833  SCIP* scip, /**< SCIP data structure */
7834  SCIP_CONS* cons, /**< knapsack constraint */
7835  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7836  int* naddconss /**< pointer to count number of added constraints */
7837  )
7838 {
7839  SCIP_CONS* newcons;
7840  SCIP_CONSDATA* consdata;
7841 
7842  assert(scip != NULL);
7843  assert(cons != NULL);
7844  assert(ndelconss != NULL);
7845  assert(naddconss != NULL);
7846 
7847  consdata = SCIPconsGetData(cons);
7848  assert(consdata != NULL);
7849  assert(consdata->nvars > 1);
7850 
7851  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7852  if( consdata->nvars == 2 )
7853  {
7854  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7855 
7856  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7860  SCIPconsIsStickingAtNode(cons)) );
7861  }
7862  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7863  * containing all negated variables of the knapsack
7864  */
7865  else
7866  {
7867  SCIP_VAR** consvars;
7868 
7869  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7870 
7871  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7872  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7873 
7874  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7878  SCIPconsIsStickingAtNode(cons)) );
7879 
7880  SCIPfreeBufferArray(scip, &consvars);
7881  }
7882 
7883  SCIP_CALL( SCIPaddCons(scip, newcons) );
7884  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7885  ++(*naddconss);
7886 
7887  SCIP_CALL( SCIPdelCons(scip, cons) );
7888  ++(*ndelconss);
7889 
7890  return SCIP_OKAY;
7891 }
7892 
7893 /** delete redundant variables
7894  *
7895  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7896  *
7897  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7898  * => x4, x5 always fits into the knapsack, so we can delete them
7899  *
7900  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7901  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7902  */
7903 static
7905  SCIP* scip, /**< SCIP data structure */
7906  SCIP_CONS* cons, /**< knapsack constraint */
7907  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7908  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7909  * first which did not fit */
7910  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7911  int* nchgsides, /**< pointer to store the amount of changed sides */
7912  int* naddconss /**< pointer to count number of added constraints */
7913  )
7914 {
7915  SCIP_CONSHDLRDATA* conshdlrdata;
7916  SCIP_CONSDATA* consdata;
7917  SCIP_VAR** vars;
7918  SCIP_Longint* weights;
7919  SCIP_Longint capacity;
7920  SCIP_Longint gcd;
7921  int nvars;
7922  int w;
7923 
7924  assert(scip != NULL);
7925  assert(cons != NULL);
7926  assert(nchgcoefs != NULL);
7927  assert(nchgsides != NULL);
7928  assert(naddconss != NULL);
7929 
7930  consdata = SCIPconsGetData(cons);
7931  assert(consdata != NULL);
7932  assert(0 < frontsum && frontsum < consdata->weightsum);
7933  assert(0 < splitpos && splitpos < consdata->nvars);
7934 
7935  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7936  assert(conshdlrdata != NULL);
7937 
7938  vars = consdata->vars;
7939  weights = consdata->weights;
7940  nvars = consdata->nvars;
7941  capacity = consdata->capacity;
7942 
7943  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7944  * weight must not be sorted by their index
7945  */
7946 #ifndef NDEBUG
7947  for( w = nvars - 1; w > 0; --w )
7948  assert(weights[w] <= weights[w-1]);
7949 #endif
7950 
7951  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7952  if( consdata->nvars - 1 == splitpos )
7953  return SCIP_OKAY;
7954 
7955  assert(frontsum + weights[splitpos] > capacity);
7956 
7957  /* detect redundant variables */
7958  if( consdata->weightsum - weights[splitpos] <= capacity )
7959  {
7960  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7961  * fit
7962  */
7963  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7964 
7965  /* delete items and update capacity */
7966  for( w = nvars - 1; w > splitpos; --w )
7967  {
7968  consdata->capacity -= weights[w];
7969  SCIP_CALL( delCoefPos(scip, cons, w) );
7970  }
7971  assert(w == splitpos);
7972 
7973  ++(*nchgsides);
7974  *nchgcoefs += (nvars - splitpos);
7975 
7976  /* division by greatest common divisor */
7977  gcd = weights[w];
7978  for( ; w >= 0 && gcd > 1; --w )
7979  {
7980  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7981  }
7982 
7983  /* normalize if possible */
7984  if( gcd > 1 )
7985  {
7986  for( w = splitpos; w >= 0; --w )
7987  {
7988  consdataChgWeight(consdata, w, weights[w]/gcd);
7989  }
7990  (*nchgcoefs) += nvars;
7991 
7992  consdata->capacity /= gcd;
7993  ++(*nchgsides);
7994  }
7995 
7996  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7997  * weight must not be sorted by their index
7998  */
7999 #ifndef NDEBUG
8000  for( w = consdata->nvars - 1; w > 0; --w )
8001  assert(weights[w] <= weights[w - 1]);
8002 #endif
8003  }
8004  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8005  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8006  * splitpos and needs to fit into the knapsack
8007  */
8008  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8009  {
8010  int* clqpart;
8011  int nclq;
8012  int len;
8013 
8014  len = nvars - (splitpos + 1);
8015  /* allocate temporary memory */
8016  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8017 
8018  /* calculate clique partition */
8019  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8020 
8021  /* check if we found at least one clique */
8022  if( nclq < len )
8023  {
8024  SCIP_Longint maxactduetoclq;
8025  int cliquenum;
8026 
8027  maxactduetoclq = 0;
8028  cliquenum = 0;
8029 
8030  /* calculate maximum activity due to cliques */
8031  for( w = 0; w < len; ++w )
8032  {
8033  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8034  if( clqpart[w] == cliquenum )
8035  {
8036  maxactduetoclq += weights[w + splitpos + 1];
8037  ++cliquenum;
8038  }
8039  }
8040 
8041  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8042  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8043  */
8044  if( frontsum + maxactduetoclq <= capacity )
8045  {
8046  SCIP_VAR** clqvars;
8047  int nclqvars;
8048  int c;
8049 
8050  assert(maxactduetoclq < weights[splitpos]);
8051 
8052  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8053 
8054  /* allocate temporary memory */
8055  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8056 
8057  for( c = 0; c < nclq; ++c )
8058  {
8059  nclqvars = 0;
8060  for( w = 0; w < len; ++w )
8061  {
8062  if( clqpart[w] == c )
8063  {
8064  clqvars[nclqvars] = vars[w + splitpos + 1];
8065  ++nclqvars;
8066  }
8067  }
8068 
8069  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8070  if( nclqvars > 1 )
8071  {
8072  SCIP_CONS* cliquecons;
8073  char name[SCIP_MAXSTRLEN];
8074 
8075  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8076  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8080  SCIPconsIsStickingAtNode(cons)) );
8081  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8082  SCIPdebugPrintCons(scip, cliquecons, NULL);
8083  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8084  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8085  ++(*naddconss);
8086  }
8087  }
8088 
8089  /* delete items and update capacity */
8090  for( w = nvars - 1; w > splitpos; --w )
8091  {
8092  SCIP_CALL( delCoefPos(scip, cons, w) );
8093  ++(*nchgcoefs);
8094  }
8095  consdata->capacity -= maxactduetoclq;
8096  assert(frontsum <= consdata->capacity);
8097  ++(*nchgsides);
8098 
8099  assert(w == splitpos);
8100 
8101  /* renew weights pointer */
8102  weights = consdata->weights;
8103 
8104  /* division by greatest common divisor */
8105  gcd = weights[w];
8106  for( ; w >= 0 && gcd > 1; --w )
8107  {
8108  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8109  }
8110 
8111  /* normalize if possible */
8112  if( gcd > 1 )
8113  {
8114  for( w = splitpos; w >= 0; --w )
8115  {
8116  consdataChgWeight(consdata, w, weights[w]/gcd);
8117  }
8118  (*nchgcoefs) += nvars;
8119 
8120  consdata->capacity /= gcd;
8121  ++(*nchgsides);
8122  }
8123 
8124  /* free temporary memory */
8125  SCIPfreeBufferArray(scip, &clqvars);
8126 
8127  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8128  * weight must not be sorted by their index
8129  */
8130 #ifndef NDEBUG
8131  for( w = consdata->nvars - 1; w > 0; --w )
8132  assert(weights[w] <= weights[w - 1]);
8133 #endif
8134  }
8135  }
8136 
8137  /* free temporary memory */
8138  SCIPfreeBufferArray(scip, &clqpart);
8139  }
8140 
8141  return SCIP_OKAY;
8142 }
8143 
8144 /* detect redundant variables which always fits into the knapsack
8145  *
8146  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8147  *
8148  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8149  * => x4, x5 always fits into the knapsack, so we can delete them
8150  *
8151  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8152  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8153  */
8154 static
8156  SCIP* scip, /**< SCIP data structure */
8157  SCIP_CONS* cons, /**< knapsack constraint */
8158  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8159  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8160  int* nchgsides, /**< pointer to store the amount of changed sides */
8161  int* naddconss /**< pointer to count number of added constraints */
8162  )
8164  SCIP_CONSHDLRDATA* conshdlrdata;
8165  SCIP_CONSDATA* consdata;
8166  SCIP_VAR** vars;
8167  SCIP_Longint* weights;
8168  SCIP_Longint capacity;
8169  SCIP_Longint sum;
8170  int noldchgcoefs;
8171  int nvars;
8172  int v;
8173  int w;
8174 
8175  assert(scip != NULL);
8176  assert(cons != NULL);
8177  assert(ndelconss != NULL);
8178  assert(nchgcoefs != NULL);
8179  assert(nchgsides != NULL);
8180  assert(naddconss != NULL);
8181 
8182  consdata = SCIPconsGetData(cons);
8183  assert(consdata != NULL);
8184  assert(consdata->nvars >= 2);
8185  assert(consdata->weightsum > consdata->capacity);
8186 
8187  noldchgcoefs = *nchgcoefs;
8188  vars = consdata->vars;
8189  weights = consdata->weights;
8190  nvars = consdata->nvars;
8191  capacity = consdata->capacity;
8192  sum = 0;
8193 
8194  /* search for maximal fitting items */
8195  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8196  sum += weights[v];
8197 
8198  assert(v < nvars);
8199 
8200  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8201  if( v == nvars - 1 )
8202  {
8203  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8204  assert(SCIPconsIsDeleted(cons));
8205 
8206  return SCIP_OKAY;
8207  }
8208 
8209  if( v < nvars - 1 )
8210  {
8211  /* try to delete variables */
8212  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8213  assert(consdata->nvars > 1);
8214 
8215  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8216  if( v == consdata->nvars - 1 )
8217  {
8218  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8219  assert(SCIPconsIsDeleted(cons));
8220  }
8221 
8222  return SCIP_OKAY;
8223  }
8224 
8225  /* if we already found some redundant variables, stop here */
8226  if( *nchgcoefs > noldchgcoefs )
8227  return SCIP_OKAY;
8228 
8229  assert(vars == consdata->vars);
8230  assert(weights == consdata->weights);
8231  assert(nvars == consdata->nvars);
8232  assert(capacity == consdata->capacity);
8233 
8234  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8235  assert(conshdlrdata != NULL);
8236  /* calculate clique partition */
8237  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8238 
8239  /* check for real existing cliques */
8240  if( consdata->cliquepartition[v] < v )
8241  {
8242  SCIP_Longint sumfront;
8243  SCIP_Longint maxactduetoclqfront;
8244  int* clqpart;
8245  int cliquenum;
8246 
8247  sumfront = 0;
8248  maxactduetoclqfront = 0;
8249 
8250  clqpart = consdata->cliquepartition;
8251  cliquenum = 0;
8252 
8253  /* calculate maximal activity due to cliques */
8254  for( w = 0; w < nvars; ++w )
8255  {
8256  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8257  if( clqpart[w] == cliquenum )
8258  {
8259  if( maxactduetoclqfront + weights[w] <= capacity )
8260  {
8261  maxactduetoclqfront += weights[w];
8262  ++cliquenum;
8263  }
8264  else
8265  break;
8266  }
8267  sumfront += weights[w];
8268  }
8269  assert(w >= v);
8270 
8271  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8272  * information
8273  */
8274  if( conshdlrdata->disaggregation && w == nvars )
8275  {
8276  SCIP_VAR** clqvars;
8277  int nclqvars;
8278  int c;
8279  int ncliques;
8280 
8281  assert(maxactduetoclqfront <= capacity);
8282 
8283  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8284 
8285  ncliques = consdata->ncliques;
8286 
8287  /* allocate temporary memory */
8288  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8289 
8290  for( c = 0; c < ncliques; ++c )
8291  {
8292  nclqvars = 0;
8293  for( w = 0; w < nvars; ++w )
8294  {
8295  if( clqpart[w] == c )
8296  {
8297  clqvars[nclqvars] = vars[w];
8298  ++nclqvars;
8299  }
8300  }
8301 
8302  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8303  if( nclqvars > 1 )
8304  {
8305  SCIP_CONS* cliquecons;
8306  char name[SCIP_MAXSTRLEN];
8307 
8308  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8309  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8313  SCIPconsIsStickingAtNode(cons)) );
8314  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8315  SCIPdebugPrintCons(scip, cliquecons, NULL);
8316  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8317  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8318  ++(*naddconss);
8319  }
8320  }
8321 
8322  /* delete old constraint */
8323  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8324  ++(*ndelconss);
8325 
8326  SCIPfreeBufferArray(scip, &clqvars);
8327 
8328  return SCIP_OKAY;
8329  }
8330 
8331  if( w > v && w < nvars - 1 )
8332  {
8333  /* try to delete variables */
8334  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8335  }
8336  }
8337 
8338  return SCIP_OKAY;
8339 }
8340 
8341 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8342 static
8343 void normalizeWeights(
8344  SCIP_CONS* cons, /**< knapsack constraint */
8345  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8346  int* nchgsides /**< pointer to count number of side changes */
8347  )
8348 {
8349  SCIP_CONSDATA* consdata;
8350  SCIP_Longint gcd;
8351  int i;
8352 
8353  assert(nchgcoefs != NULL);
8354  assert(nchgsides != NULL);
8355  assert(!SCIPconsIsModifiable(cons));
8356 
8357  consdata = SCIPconsGetData(cons);
8358  assert(consdata != NULL);
8359  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8360  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8361  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8362  assert(consdata->nvars >= 1);
8363 
8364  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8365  sortItems(consdata);
8366 
8367  gcd = consdata->weights[consdata->nvars-1];
8368  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8369  {
8370  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8371  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8372 
8373  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8374  }
8375 
8376  if( gcd >= 2 )
8377  {
8378  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8379 
8380  for( i = 0; i < consdata->nvars; ++i )
8381  {
8382  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8383  }
8384  consdata->capacity /= gcd;
8385  (*nchgcoefs) += consdata->nvars;
8386  (*nchgsides)++;
8387 
8388  /* weight should still be sorted, because the reduction preserves this */
8389 #ifndef NDEBUG
8390  for( i = consdata->nvars - 1; i > 0; --i )
8391  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8392 #endif
8393  consdata->sorted = TRUE;
8394  }
8395 }
8396 
8397 /** dual weights tightening for knapsack constraints
8398  *
8399  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8400  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8401  * constraint
8402  *
8403  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8404  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8405  *
8406  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8407  *
8408  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8409  *
8410  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8411  *
8412  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8413  *
8414  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8415  */
8416 static
8418  SCIP* scip, /**< SCIP data structure */
8419  SCIP_CONS* cons, /**< knapsack constraint */
8420  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8421  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8422  int* nchgsides, /**< pointer to store the amount of changed sides */
8423  int* naddconss /**< pointer to count number of added constraints */
8424  )
8426  SCIP_CONSDATA* consdata;
8427  SCIP_Longint* weights;
8428  SCIP_Longint dualcapacity;
8429  SCIP_Longint reductionsum;
8430  SCIP_Longint capacity;
8431  SCIP_Longint exceedsum;
8432  int oldnchgcoefs;
8433  int nvars;
8434  int vbig;
8435  int v;
8436  int w;
8437 #ifndef NDEBUG
8438  int oldnchgsides;
8439 #endif
8440 
8441  assert(scip != NULL);
8442  assert(cons != NULL);
8443  assert(ndelconss != NULL);
8444  assert(nchgcoefs != NULL);
8445  assert(nchgsides != NULL);
8446  assert(naddconss != NULL);
8447 
8448 #ifndef NDEBUG
8449  oldnchgsides = *nchgsides;
8450 #endif
8451 
8452  consdata = SCIPconsGetData(cons);
8453  assert(consdata != NULL);
8454  assert(consdata->weightsum > consdata->capacity);
8455  assert(consdata->nvars >= 2);
8456  assert(consdata->sorted);
8457 
8458  /* constraint should be merged */
8459  assert(consdata->merged);
8460 
8461  nvars = consdata->nvars;
8462  weights = consdata->weights;
8463  capacity = consdata->capacity;
8464 
8465  oldnchgcoefs = *nchgcoefs;
8466 
8467  /* case 1. */
8468  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8469  {
8470  SCIP_CONS* newcons;
8471 
8472  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8473  *
8474  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8475  */
8476  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8477 
8478  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8482  SCIPconsIsStickingAtNode(cons)) );
8483 
8484  SCIP_CALL( SCIPaddCons(scip, newcons) );
8485  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8486  ++(*naddconss);
8487 
8488  SCIP_CALL( SCIPdelCons(scip, cons) );
8489  ++(*ndelconss);
8490 
8491  return SCIP_OKAY;
8492  }
8493 
8494  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8495  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8496  {
8497  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8498  assert(SCIPconsIsDeleted(cons));
8499 
8500  return SCIP_OKAY;
8501  }
8502 
8503  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8504  /* @todo might be changed/removed when improving the coeffcients tightening */
8505  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8506  return SCIP_OKAY;
8507 
8508  /* case 2. */
8509 
8510  v = 0;
8511 
8512  /* @todo generalize the following algorithm for several parts of the knapsack
8513  *
8514  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8515  * variables each combination is a minimal cover, some examples
8516  *
8517  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8518  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8519  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8520  *
8521  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8522  *
8523  */
8524 
8525  /* determine big weights that fit only by itself */
8526  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8527  ++v;
8528 
8529  vbig = v;
8530  assert(vbig < nvars - 1);
8531  exceedsum = 0;
8532 
8533  /* determine the amount needed to exceed the capacity */
8534  while( v < nvars && exceedsum <= capacity )
8535  {
8536  exceedsum += weights[v];
8537  ++v;
8538  }
8539 
8540  /* if we exceeded the capacity we might reduce the weights */
8541  if( exceedsum > capacity )
8542  {
8543  assert(vbig > 0 || v < nvars);
8544 
8545  /* all small weights were needed to exceed the capacity */
8546  if( v == nvars )
8547  {
8548  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8549  assert(newweight > 0);
8550 
8551  /* reduce big weights */
8552  for( v = 0; v < vbig; ++v )
8553  {
8554  if( weights[v] > newweight )
8555  {
8556  consdataChgWeight(consdata, v, newweight);
8557  ++(*nchgcoefs);
8558  }
8559  }
8560 
8561  /* reduce small weights */
8562  for( ; v < nvars; ++v )
8563  {
8564  if( weights[v] > 1 )
8565  {
8566  consdataChgWeight(consdata, v, 1LL);
8567  ++(*nchgcoefs);
8568  }
8569  }
8570 
8571  consdata->capacity = newweight;
8572 
8573  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8574  * weight must not be sorted by their index
8575  */
8576 #ifndef NDEBUG
8577  for( v = nvars - 1; v > 0; --v )
8578  assert(weights[v] <= weights[v-1]);
8579 #endif
8580 
8581  return SCIP_OKAY;
8582  }
8583  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8584  * small weights
8585  */
8586  else
8587  {
8588  SCIP_Longint exceedsumback = 0;
8589  int nexceed = v - vbig;
8590 
8591  assert(nexceed > 1);
8592 
8593  /* determine weightsum of the same amount as before but of the smallest weight */
8594  for( w = nvars - 1; w >= nvars - nexceed; --w )
8595  exceedsumback += weights[w];
8596 
8597  assert(w >= 0);
8598 
8599  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8600  * combinations of all small weights
8601  */
8602  if( exceedsumback > capacity )
8603  {
8604  SCIP_Longint newweight = nexceed - 1;
8605 
8606  /* taking out the smallest element needs to fit */
8607  assert(exceedsumback - weights[nvars - 1] <= capacity);
8608 
8609  /* reduce big weights */
8610  for( v = 0; v < vbig; ++v )
8611  {
8612  if( weights[v] > newweight )
8613  {
8614  consdataChgWeight(consdata, v, newweight);
8615  ++(*nchgcoefs);
8616  }
8617  }
8618 
8619  /* reduce small weights */
8620  for( ; v < nvars; ++v )
8621  {
8622  if( weights[v] > 1 )
8623  {
8624  consdataChgWeight(consdata, v, 1LL);
8625  ++(*nchgcoefs);
8626  }
8627  }
8628 
8629  consdata->capacity = newweight;
8630 
8631  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8632  * weight must not be sorted by their index
8633  */
8634 #ifndef NDEBUG
8635  for( v = nvars - 1; v > 0; --v )
8636  assert(weights[v] <= weights[v-1]);
8637 #endif
8638  return SCIP_OKAY;
8639  }
8640  }
8641  }
8642  else
8643  {
8644  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8645  * not happen here
8646  */
8647  assert(vbig > 0 && vbig < nvars);
8648 
8649  /* either choose a big coefficients or all other variables
8650  *
8651  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8652  *
8653  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8654  * constraint to
8655  *
8656  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8657  */
8658 
8659  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8660  {
8661  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8662 #ifndef NDEBUG
8663  SCIP_Longint resweightsum = consdata->weightsum;
8664 
8665  for( v = 0; v < vbig; ++v )
8666  resweightsum -= weights[v];
8667 
8668  assert(exceedsum == resweightsum);
8669 #endif
8670  assert(newweight > 0);
8671 
8672  /* reduce big weights */
8673  for( v = 0; v < vbig; ++v )
8674  {
8675  if( weights[v] > newweight )
8676  {
8677  consdataChgWeight(consdata, v, newweight);
8678  ++(*nchgcoefs);
8679  }
8680  }
8681 
8682  /* reduce small weights */
8683  for( ; v < nvars; ++v )
8684  {
8685  if( weights[v] > 1 )
8686  {
8687  consdataChgWeight(consdata, v, 1LL);
8688  ++(*nchgcoefs);
8689  }
8690  }
8691 
8692  consdata->capacity = newweight;
8693 
8694  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8695  * weight must not be sorted by their index
8696  */
8697 #ifndef NDEBUG
8698  for( v = nvars - 1; v > 0; --v )
8699  assert(weights[v] <= weights[v-1]);
8700 #endif
8701  return SCIP_OKAY;
8702  }
8703  }
8704 
8705  /* case 3. */
8706 
8707  dualcapacity = consdata->weightsum - capacity;
8708  reductionsum = 0;
8709  v = 0;
8710 
8711  /* reduce big weights
8712  *
8713  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8714  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8715  * <=> x0 + x1 + x2 + x3 <= 3
8716  */
8717  while( weights[v] > dualcapacity )
8718  {
8719  reductionsum += (weights[v] - dualcapacity);
8720  consdataChgWeight(consdata, v, dualcapacity);
8721  ++v;
8722  assert(v < nvars);
8723  }
8724  (*nchgcoefs) += v;
8725 
8726  /* skip weights equal to the dualcapacity, because we cannot change them */
8727  while( v < nvars && weights[v] == dualcapacity )
8728  ++v;
8729 
8730  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8731  * after a possible removal of the last, redundant item
8732  *
8733  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8734  */
8735  if( v >= nvars - 1 )
8736  {
8737  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8738  if( v == nvars - 1 )
8739  {
8740  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8741  }
8742  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8743  assert(SCIPconsIsDeleted(cons));
8744 
8745  return SCIP_OKAY;
8746  }
8747  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8748  {
8749  /* @todo generalize the following algorithm for more than two variables */
8750 
8751  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8752  {
8753  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8754  * coefficients) of all or two variables of the rest
8755  *
8756  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8757  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8758  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8759  *
8760  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8761  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8762  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8763  *
8764  */
8765  if( v > 0 && weights[nvars - 2] > 1 )
8766  {
8767  int ncoefchg = 0;
8768 
8769  /* reduce all bigger weights */
8770  for( w = 0; w < v; ++w )
8771  {
8772  if( weights[w] > 2 )
8773  {
8774  consdataChgWeight(consdata, w, 2LL);
8775  ++ncoefchg;
8776  }
8777  else
8778  {
8779  assert(weights[0] == 2);
8780  assert(weights[v - 1] == 2);
8781  break;
8782  }
8783  }
8784 
8785  /* reduce all smaller weights */
8786  for( w = v; w < nvars; ++w )
8787  {
8788  if( weights[w] > 1 )
8789  {
8790  consdataChgWeight(consdata, w, 1LL);
8791  ++ncoefchg;
8792  }
8793  }
8794  assert(ncoefchg > 0);
8795 
8796  (*nchgcoefs) += ncoefchg;
8797 
8798  /* correct the capacity */
8799  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8800  assert(consdata->capacity > 0);
8801  assert(weights[0] <= consdata->capacity);
8802  assert(consdata->weightsum > consdata->capacity);
8803  /* reset the reductionsum */
8804  reductionsum = 0;
8805  }
8806  else if( v == 0 )
8807  {
8808  assert(weights[nvars - 2] == 1);
8809  }
8810  }
8811  else
8812  {
8813  SCIP_Longint minweight = weights[nvars - 1];
8814  SCIP_Longint newweight = dualcapacity - minweight;
8815  SCIP_Longint restsumweights = 0;
8816  SCIP_Longint sumcoef;
8817  SCIP_Bool sumcoefcase = FALSE;
8818  int startv = v;
8819  int end;
8820  int k;
8821 
8822  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8823 
8824  /* reduce big weights of pairs that exceed the dualcapacity
8825  *
8826  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8827  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8828  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8829  */
8830  while( weights[v] > newweight )
8831  {
8832  reductionsum += (weights[v] - newweight);
8833  consdataChgWeight(consdata, v, newweight);
8834  ++v;
8835  assert(v < nvars);
8836  }
8837  (*nchgcoefs) += (v - startv);
8838 
8839  /* skip equal weights */
8840  while( weights[v] == newweight )
8841  ++v;
8842 
8843  if( v > 0 )
8844  {
8845  for( w = v; w < nvars; ++w )
8846  restsumweights += weights[w];
8847  }
8848  else
8849  restsumweights = consdata->weightsum;
8850 
8851  if( restsumweights < dualcapacity )
8852  {
8853  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8854  *
8855  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8856  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8857  */
8858  if( startv == v )
8859  {
8860  /* remove redundant variables */
8861  for( w = nvars - 1; w >= v; --w )
8862  {
8863  SCIP_CALL( delCoefPos(scip, cons, v) );
8864  ++(*nchgcoefs);
8865  }
8866 
8867 #ifndef NDEBUG
8868  /* each coefficients should exceed the dualcapacity by itself */
8869  for( ; w >= 0; --w )
8870  assert(weights[w] == dualcapacity);
8871 #endif
8872  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8873  * upgrade this constraint
8874  */
8875  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8876  assert(SCIPconsIsDeleted(cons));
8877 
8878  return SCIP_OKAY;
8879  }
8880 
8881  /* special case where we have three different coefficient types
8882  *
8883  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8884  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8885  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8886  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8887  */
8888  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8889  {
8890  SCIP_Longint newcap;
8891 
8892  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8893  for( w = nvars - 1; w >= v; --w )
8894  {
8895  if( weights[w] > 1 )
8896  {
8897  consdataChgWeight(consdata, w, 1LL);
8898  ++(*nchgcoefs);
8899  }
8900  }
8901 
8902  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8903  * dualcapacity
8904  */
8905  newweight = (SCIP_Longint)nvars - v;
8906  assert(newweight > 1);
8907  for( ; w >= startv; --w )
8908  {
8909  if( weights[w] > newweight )
8910  {
8911  consdataChgWeight(consdata, w, newweight);
8912  ++(*nchgcoefs);
8913  }
8914  else
8915  assert(weights[w] == newweight);
8916  }
8917 
8918  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8919  ++newweight;
8920  assert(newweight > 2);
8921  for( ; w >= 0; --w )
8922  {
8923  if( weights[w] > newweight )
8924  {
8925  consdataChgWeight(consdata, w, newweight);
8926  ++(*nchgcoefs);
8927  }
8928  else
8929  assert(weights[w] == newweight);
8930  }
8931 
8932  /* update the capacity */
8933  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8934  if( consdata->capacity > newcap )
8935  {
8936  consdata->capacity = newcap;
8937  ++(*nchgsides);
8938  }
8939  else
8940  assert(consdata->capacity == newcap);
8941  }
8942  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8943 
8944  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8945  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8946 
8947  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8948  * weight must not be sorted by their index
8949  */
8950 #ifndef NDEBUG
8951  for( w = nvars - 1; w > 0; --w )
8952  assert(weights[w] <= weights[w - 1]);
8953 #endif
8954  return SCIP_OKAY;
8955  }
8956 
8957  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8958  end = nvars - 2;
8959  while( end >= 0 && weights[end] == weights[end + 1] )
8960  {
8961  assert(end >= v);
8962  --end;
8963  }
8964 
8965  if( v >= end )
8966  goto TERMINATE;
8967 
8968  end = nvars - 2;
8969 
8970  /* can we stop early, another special reduction case might exist */
8971  if( 2 * weights[end] > dualcapacity )
8972  {
8973  restsumweights = 0;
8974 
8975  /* determine capacity of the small items */
8976  for( w = end + 1; w < nvars; ++w )
8977  restsumweights += weights[w];
8978 
8979  if( restsumweights * 2 <= dualcapacity )
8980  {
8981  /* check for further posssible reductions in the middle */
8982  while( v < end && restsumweights + weights[v] >= dualcapacity )
8983  ++v;
8984 
8985  if( v >= end )
8986  goto TERMINATE;
8987 
8988  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8989  if( (dualcapacity & 1) == 0 )
8990  {
8991  newweight = dualcapacity / 2;
8992 
8993  /* set all middle coefficients */
8994  for( ; v <= end; ++v )
8995  {
8996  if( weights[v] > newweight )
8997  {
8998  reductionsum += (weights[v] - newweight);
8999  consdataChgWeight(consdata, v, newweight);
9000  ++(*nchgcoefs);
9001  }
9002  }
9003  }
9004  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9005  * other coefficients by 2
9006  */
9007  else
9008  {
9009  /* correct the reductionsum */
9010  reductionsum *= 2;
9011 
9012  /* multiply big coefficients by 2 */
9013  for( w = 0; w < v; ++w )
9014  {
9015  consdataChgWeight(consdata, w, weights[w] * 2);
9016  }
9017 
9018  newweight = dualcapacity;
9019  /* set all middle coefficients */
9020  for( ; v <= end; ++v )
9021  {
9022  reductionsum += (2 * weights[v] - newweight);
9023  consdataChgWeight(consdata, v, newweight);
9024  }
9025 
9026  /* multiply small coefficients by 2 */
9027  for( w = end + 1; w < nvars; ++w )
9028  {
9029  consdataChgWeight(consdata, w, weights[w] * 2);
9030  }
9031  (*nchgcoefs) += nvars;
9032 
9033  dualcapacity *= 2;
9034  consdata->capacity *= 2;
9035  ++(*nchgsides);
9036  }
9037  }
9038 
9039  goto TERMINATE;
9040  }
9041 
9042  /* further reductions using the next possible coefficient sum
9043  *
9044  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9045  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9046  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9047  */
9048  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9049  for( k = 0; k < 4; ++k )
9050  {
9051  /* determine next minimal coefficient sum */
9052  switch( k )
9053  {
9054  case 0:
9055  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9056  break;
9057  case 1:
9058  assert(nvars >= 3);
9059  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9060  break;
9061  case 2:
9062  assert(nvars >= 4);
9063  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9064  {
9065  sumcoefcase = TRUE;
9066  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9067  }
9068  else
9069  {
9070  sumcoefcase = FALSE;
9071  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9072  }
9073  break;
9074  case 3:
9075  assert(nvars >= 5);
9076  if( sumcoefcase )
9077  {
9078  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9079  }
9080  else
9081  {
9082  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9083  }
9084  break;
9085  default:
9086  return SCIP_ERROR;
9087  }
9088 
9089  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9090  minweight = weights[end];
9091  while( minweight <= sumcoef )
9092  {
9093  newweight = dualcapacity - minweight;
9094  startv = v;
9095  assert(v < nvars);
9096 
9097  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9098  /* shrink big coefficients */
9099  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9100  {
9101  reductionsum += (weights[v] - newweight);
9102  consdataChgWeight(consdata, v, newweight);
9103  ++v;
9104  assert(v < nvars);
9105  }
9106  (*nchgcoefs) += (v - startv);
9107 
9108  /* skip unchangable weights */
9109  while( weights[v] + minweight == dualcapacity )
9110  {
9111  assert(v < nvars);
9112  ++v;
9113  }
9114 
9115  --end;
9116  /* skip same end weights */
9117  while( end >= 0 && weights[end] == weights[end + 1] )
9118  --end;
9119 
9120  if( v >= end )
9121  goto TERMINATE;
9122 
9123  minweight = weights[end];
9124  }
9125 
9126  if( v >= end )
9127  goto TERMINATE;
9128 
9129  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9130  if( sumcoef < minweight )
9131  {
9132  minweight = sumcoef;
9133  newweight = dualcapacity - minweight;
9134  startv = v;
9135  assert(v < nvars);
9136 
9137  /* shrink big coefficients */
9138  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9139  {
9140  reductionsum += (weights[v] - newweight);
9141  consdataChgWeight(consdata, v, newweight);
9142  ++v;
9143  assert(v < nvars);
9144  }
9145  (*nchgcoefs) += (v - startv);
9146 
9147  /* skip unchangable weights */
9148  while( weights[v] + minweight == dualcapacity )
9149  {
9150  assert(v < nvars);
9151  ++v;
9152  }
9153  }
9154 
9155  if( v >= end )
9156  goto TERMINATE;
9157 
9158  /* can we stop early, another special reduction case might exist */
9159  if( 2 * weights[end] > dualcapacity )
9160  {
9161  restsumweights = 0;
9162 
9163  /* determine capacity of the small items */
9164  for( w = end + 1; w < nvars; ++w )
9165  restsumweights += weights[w];
9166 
9167  if( restsumweights * 2 <= dualcapacity )
9168  {
9169  /* check for further posssible reductions in the middle */
9170  while( v < end && restsumweights + weights[v] >= dualcapacity )
9171  ++v;
9172 
9173  if( v >= end )
9174  goto TERMINATE;
9175 
9176  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9177  if( (dualcapacity & 1) == 0 )
9178  {
9179  newweight = dualcapacity / 2;
9180 
9181  /* set all middle coefficients */
9182  for( ; v <= end; ++v )
9183  {
9184  if( weights[v] > newweight )
9185  {
9186  reductionsum += (weights[v] - newweight);
9187  consdataChgWeight(consdata, v, newweight);
9188  ++(*nchgcoefs);
9189  }
9190  }
9191  }
9192  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9193  * other coefficients by 2
9194  */
9195  else
9196  {
9197  /* correct the reductionsum */
9198  reductionsum *= 2;
9199 
9200  /* multiply big coefficients by 2 */
9201  for( w = 0; w < v; ++w )
9202  {
9203  consdataChgWeight(consdata, w, weights[w] * 2);
9204  }
9205 
9206  newweight = dualcapacity;
9207  /* set all middle coefficients */
9208  for( ; v <= end; ++v )
9209  {
9210  reductionsum += (2 * weights[v] - newweight);
9211  consdataChgWeight(consdata, v, newweight);
9212  }
9213 
9214  /* multiply small coefficients by 2 */
9215  for( w = end + 1; w < nvars; ++w )
9216  {
9217  consdataChgWeight(consdata, w, weights[w] * 2);
9218  }
9219  (*nchgcoefs) += nvars;
9220 
9221  dualcapacity *= 2;
9222  consdata->capacity *= 2;
9223  ++(*nchgsides);
9224  }
9225  }
9226 
9227  goto TERMINATE;
9228  }
9229 
9230  /* cannot tighten any further */
9231  if( 2 * sumcoef > dualcapacity )
9232  goto TERMINATE;
9233  }
9234  }
9235  }
9236 
9237  TERMINATE:
9238  /* correct capacity */
9239  if( reductionsum > 0 )
9240  {
9241  assert(v > 0);
9242 
9243  consdata->capacity -= reductionsum;
9244  ++(*nchgsides);
9245 
9246  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9247  }
9248  assert(weights[0] <= consdata->capacity);
9249 
9250  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9251  * weight must not be sorted by their index
9252  */
9253 #ifndef NDEBUG
9254  for( w = nvars - 1; w > 0; --w )
9255  assert(weights[w] <= weights[w - 1]);
9256 #endif
9257 
9258  if( oldnchgcoefs < *nchgcoefs )
9259  {
9260  assert(!SCIPconsIsDeleted(cons));
9261 
9262  /* it might be that we can divide the weights by their greatest common divisor */
9263  normalizeWeights(cons, nchgcoefs, nchgsides);
9264  }
9265  else
9266  {
9267  assert(oldnchgcoefs == *nchgcoefs);
9268  assert(oldnchgsides == *nchgsides);
9269  }
9270 
9271  return SCIP_OKAY;
9272 }
9273 
9274 
9275 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9276 static
9278  SCIP* scip, /**< SCIP data structure */
9279  SCIP_CONS* cons, /**< knapsack constraint */
9280  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9281  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9282  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9283  )
9284 {
9285  SCIP_VAR** vars;
9286  SCIP_CONSDATA* consdata;
9287  SCIP_Longint* weights;
9288  SCIP_Longint capacity;
9289  SCIP_Bool infeasible;
9290  SCIP_Bool fixed;
9291  int nvars;
9292  int v;
9293 
9294  assert(scip != NULL);
9295  assert(cons != NULL);
9296  assert(nfixedvars != NULL);
9297  assert(ndelconss != NULL);
9298  assert(nchgcoefs != NULL);
9299 
9300  consdata = SCIPconsGetData(cons);
9301  assert(consdata != NULL);
9302 
9303  nvars = consdata->nvars;
9304 
9305  /* no variables left, then delete constraint */
9306  if( nvars == 0 )
9307  {
9308  assert(consdata->capacity >= 0);
9309 
9310  SCIP_CALL( SCIPdelCons(scip, cons) );
9311  ++(*ndelconss);
9312 
9313  return SCIP_OKAY;
9314  }
9315 
9316  /* sort items */
9317  sortItems(consdata);
9318 
9319  vars = consdata->vars;
9320  weights = consdata->weights;
9321  capacity = consdata->capacity;
9322  v = 0;
9323 
9324  /* check for weights bigger than the capacity */
9325  while( v < nvars && weights[v] > capacity )
9326  {
9327  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9328  assert(!infeasible);
9329 
9330  if( fixed )
9331  ++(*nfixedvars);
9332 
9333  ++v;
9334  }
9335 
9336  /* if we fixed at least one variable we need to delete them from the constraint */
9337  if( v > 0 )
9338  {
9339  if( v == nvars )
9340  {
9341  SCIP_CALL( SCIPdelCons(scip, cons) );
9342  ++(*ndelconss);
9343 
9344  return SCIP_OKAY;
9345  }
9346 
9347  /* delete all position from back to front */
9348  for( --v; v >= 0; --v )
9349  {
9350  SCIP_CALL( delCoefPos(scip, cons, v) );
9351  ++(*nchgcoefs);
9352  }
9353 
9354  /* sort items again because of deletion */
9355  sortItems(consdata);
9356  assert(vars == consdata->vars);
9357  assert(weights == consdata->weights);
9358  }
9359  assert(consdata->sorted);
9360  assert(weights[0] <= capacity);
9361 
9362  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9363  {
9364  SCIP_CALL( SCIPdelCons(scip, cons) );
9365  ++(*ndelconss);
9366  }
9367 
9368  return SCIP_OKAY;
9369 }
9370 
9371 
9372 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9373  *
9374  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9375  *
9376  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9377  *
9378  * the above constraint can be changed to
9379  *
9380  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9381  *
9382  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9383  *
9384  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9385  *
9386  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9387  * constraint further, e.g.
9388  *
9389  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9390  * => 2x1 + x2 + x3 + x4 <= 2
9391  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9392  */
9393 static
9395  SCIP* scip, /**< SCIP data structure */
9396  SCIP_CONS* cons, /**< knapsack constraint */
9397  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9398  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9399  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9400  int* nchgsides, /**< pointer to store the amount of changed sides */
9401  int* naddconss, /**< pointer to count number of added constraints */
9402  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9403  )
9404 {
9405  SCIP_VAR** vars;
9406  SCIP_CONSDATA* consdata;
9407  SCIP_Longint* weights;
9408  SCIP_Longint restweight;
9409  SCIP_Longint newweight;
9410  SCIP_Longint weight;
9411  SCIP_Longint oldgcd;
9412  SCIP_Longint rest;
9413  SCIP_Longint gcd;
9414  int oldnchgcoefs;
9415  int oldnchgsides;
9416  int candpos;
9417  int candpos2;
9418  int offsetv;
9419  int nvars;
9420  int v;
9421 
9422  assert(scip != NULL);
9423  assert(cons != NULL);
9424  assert(nfixedvars != NULL);
9425  assert(ndelconss != NULL);
9426  assert(nchgcoefs != NULL);
9427  assert(nchgsides != NULL);
9428  assert(naddconss != NULL);
9429  assert(cutoff != NULL);
9430  assert(!SCIPconsIsModifiable(cons));
9431 
9432  consdata = SCIPconsGetData(cons);
9433  assert( consdata != NULL );
9434 
9435  *cutoff = FALSE;
9436 
9437  /* remove double enties and also combinations of active and negated variables */
9438  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9439  assert(consdata->merged);
9440  if( *cutoff )
9441  return SCIP_OKAY;
9442 
9443  assert(consdata->capacity >= 0);
9444 
9445  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9446  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9447 
9448  if( SCIPconsIsDeleted(cons) )
9449  return SCIP_OKAY;
9450 
9451  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9452  {
9453  /* 1. dual weights tightening */
9454  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9455 
9456  if( SCIPconsIsDeleted(cons) )
9457  return SCIP_OKAY;
9458  /* 2. delete redundant variables */
9459  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9460 
9461  if( SCIPconsIsDeleted(cons) )
9462  return SCIP_OKAY;
9463  }
9464 
9465  weights = consdata->weights;
9466  nvars = consdata->nvars;
9467 
9468 #ifndef NDEBUG
9469  /* constraint might not be sorted, but the weights are already sorted */
9470  for( v = nvars - 1; v > 0; --v )
9471  assert(weights[v] <= weights[v-1]);
9472 #endif
9473 
9474  /* determine greatest common divisor */
9475  gcd = weights[nvars - 1];
9476  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9477  {
9478  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9479  }
9480 
9481  /* divide the constraint by their greatest common divisor */
9482  if( gcd >= 2 )
9483  {
9484  for( v = nvars - 1; v >= 0; --v )
9485  {
9486  consdataChgWeight(consdata, v, weights[v]/gcd);
9487  }
9488  (*nchgcoefs) += nvars;
9489 
9490  consdata->capacity /= gcd;
9491  (*nchgsides)++;
9492  }
9493  assert(consdata->nvars == nvars);
9494 
9495  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9496  * must not be sorted by their index
9497  */
9498 #ifndef NDEBUG
9499  for( v = nvars - 1; v > 0; --v )
9500  assert(weights[v] <= weights[v-1]);
9501 #endif
9502 
9503  /* 3. start gcd procedure for all variables */
9504  do
9505  {
9506  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9507  SCIPdebug( oldnchgsides = *nchgsides; )
9508 
9509  vars = consdata->vars;
9510  weights = consdata->weights;
9511  nvars = consdata->nvars;
9512 
9513  /* stop if we have two coefficients which are one in absolute value */
9514  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9515  return SCIP_OKAY;
9516 
9517  v = 0;
9518  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9519  * gcd
9520  */
9521  while( weights[v] == consdata->capacity )
9522  {
9523  ++v;
9524  assert(v < nvars);
9525  }
9526 
9527  /* all but one variable are as big as the capacity, this is handled elsewhere */
9528  if( v == nvars - 1 )
9529  return SCIP_OKAY;
9530 
9531  offsetv = v;
9532 
9533  gcd = -1;
9534  candpos = -1;
9535  candpos2 = -1;
9536 
9537  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9538  * change the coefficient
9539  */
9540  for( v = nvars - 1; v >= offsetv; --v )
9541  {
9542  weight = weights[v];
9543  assert(weight >= 1);
9544 
9545  oldgcd = gcd;
9546 
9547  if( gcd == -1 )
9548  {
9549  gcd = weights[v];
9550  assert(gcd >= 1);
9551  }
9552  else
9553  {
9554  /* calculate greatest common divisor for all variables */
9555  gcd = SCIPcalcGreComDiv(gcd, weight);
9556  }
9557 
9558  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9559  * can terminate
9560  */
9561  if( gcd == 1 )
9562  {
9563  /* found candidate */
9564  if( candpos == -1 )
9565  {
9566  gcd = oldgcd;
9567  candpos = v;
9568 
9569  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9570  if( v == nvars - 2 )
9571  candpos2 = v + 1;
9572  }
9573  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9574  else
9575  {
9576  if( candpos == v + 1 && candpos2 == v + 2 )
9577  {
9578  assert(candpos2 == nvars - 1);
9579 
9580  /* take new candidates */
9581  candpos = candpos2;
9582 
9583  /* recalculate gcd from scratch */
9584  gcd = weights[v+1];
9585  assert(gcd >= 1);
9586 
9587  /* calculate greatest common divisor for variables */
9588  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9589  if( gcd == 1 )
9590  return SCIP_OKAY;
9591  }
9592  else
9593  /* cannot determine a possible coefficient for reduction */
9594  return SCIP_OKAY;
9595  }
9596  }
9597  }
9598  assert(gcd >= 2);
9599 
9600  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9601  * further
9602  */
9603  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9604 
9605  /* determine the remainder of the capacity and the gcd */
9606  rest = consdata->capacity % gcd;
9607  assert(rest >= 0);
9608  assert(rest < gcd);
9609 
9610  if( candpos == -1 )
9611  {
9612  /* we assume that the constraint was normalized */
9613  assert(rest > 0);
9614 
9615  /* replace old with new capacity */
9616  consdata->capacity -= rest;
9617  ++(*nchgsides);
9618 
9619  /* replace old big coefficients with new capacity */
9620  for( v = 0; v < offsetv; ++v )
9621  {
9622  consdataChgWeight(consdata, v, consdata->capacity);
9623  }
9624 
9625  *nchgcoefs += offsetv;
9626  goto CONTINUE;
9627  }
9628 
9629  /* determine the remainder of the coefficient candidate and the gcd */
9630  restweight = weights[candpos] % gcd;
9631  assert(restweight >= 1);
9632  assert(restweight < gcd);
9633 
9634  /* calculate new coefficient */
9635  if( restweight > rest )
9636  newweight = weights[candpos] - restweight + gcd;
9637  else
9638  newweight = weights[candpos] - restweight;
9639 
9640  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9641 
9642  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);
9643 
9644  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9645  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9646  */
9647  if( newweight == 0 && offsetv > 0 )
9648  return SCIP_OKAY;
9649 
9650  if( rest > 0 )
9651  {
9652  /* replace old with new capacity */
9653  consdata->capacity -= rest;
9654  ++(*nchgsides);
9655 
9656  /* replace old big coefficients with new capacity */
9657  for( v = 0; v < offsetv; ++v )
9658  {
9659  consdataChgWeight(consdata, v, consdata->capacity);
9660  }
9661 
9662  *nchgcoefs += offsetv;
9663  }
9664 
9665  if( newweight == 0 )
9666  {
9667  /* delete redundant coefficient */
9668  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9669  assert(consdata->nvars == nvars - 1);
9670  --nvars;
9671  }
9672  else
9673  {
9674  /* replace old with new coefficient */
9675  consdataChgWeight(consdata, candpos, newweight);
9676  }
9677  ++(*nchgcoefs);
9678 
9679  assert(consdata->vars == vars);
9680  assert(consdata->nvars == nvars);
9681  assert(consdata->weights == weights);
9682 
9683  CONTINUE:
9684  /* now constraint can be normalized, dividing it by the gcd */
9685  for( v = nvars - 1; v >= 0; --v )
9686  {
9687  consdataChgWeight(consdata, v, weights[v]/gcd);
9688  }
9689  (*nchgcoefs) += nvars;
9690 
9691  consdata->capacity /= gcd;
9692  ++(*nchgsides);
9693 
9694  SCIPdebugPrintCons(scip, cons, NULL);
9695 
9696  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));
9697  }
9698  while( nvars >= 2 );
9699 
9700  return SCIP_OKAY;
9701 }
9702 
9703 
9704 /** inserts an element into the list of binary zero implications */
9705 static
9707  SCIP* scip, /**< SCIP data structure */
9708  int** liftcands, /**< array of the lifting candidates */
9709  int* nliftcands, /**< number of lifting candidates */
9710  int** firstidxs, /**< array of first zeroitems indices */
9711  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9712  int** zeroitems, /**< pointer to zero items array */
9713  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9714  int* zeroitemssize, /**< pointer to size of zero items array */
9715  int* nzeroitems, /**< pointer to length of zero items array */
9716  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9717  SCIP_Bool value, /**< value v of variable y in implication */
9718  int knapsackidx, /**< index of variable x in knapsack */
9719  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9720  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9721  )
9722 {
9723  int nzeros;
9724 
9725  assert(liftcands != NULL);
9726  assert(liftcands[value] != NULL);
9727  assert(nliftcands != NULL);
9728  assert(firstidxs != NULL);
9729  assert(firstidxs[value] != NULL);
9730  assert(zeroweightsums != NULL);
9731  assert(zeroweightsums[value] != NULL);
9732  assert(zeroitems != NULL);
9733  assert(nextidxs != NULL);
9734  assert(zeroitemssize != NULL);
9735  assert(nzeroitems != NULL);
9736  assert(*nzeroitems <= *zeroitemssize);
9737  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9738  assert(memlimitreached != NULL);
9739 
9740  nzeros = *nzeroitems;
9741 
9742  /* allocate enough memory */
9743  if( nzeros == *zeroitemssize )
9744  {
9745  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9746  * this can be too huge - abort on memory limit
9747  */
9748  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9749  {
9750  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9751  *zeroitemssize);
9752  *memlimitreached = TRUE;
9753  return SCIP_OKAY;
9754  }
9755  *zeroitemssize *= 2;
9756  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9757  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9758  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9759  }
9760  assert(nzeros < *zeroitemssize);
9761 
9762  if( *memlimitreached )
9763  *memlimitreached = FALSE;
9764 
9765  /* insert element */
9766  (*zeroitems)[nzeros] = knapsackidx;
9767  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9768  if( firstidxs[value][probindex] == 0 )
9769  {
9770  liftcands[value][nliftcands[value]] = probindex;
9771  ++nliftcands[value];
9772  }
9773  firstidxs[value][probindex] = nzeros;
9774  ++(*nzeroitems);
9775  zeroweightsums[value][probindex] += knapsackweight;
9776 
9777  return SCIP_OKAY;
9778 }
9779 
9780 #define MAX_CLIQUELENGTH 50
9781 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9782  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9783  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9784  * if cliqueweightsum(xi == v) < capacity:
9785  * - fixing variable xi to v would make the knapsack constraint redundant
9786  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9787  * redundancy effect:
9788  * wi' := capacity - cliqueweightsum(xi == v)
9789  * this rule can also be applied to binary variables not in the knapsack!
9790  */
9791 static
9793  SCIP* scip, /**< SCIP data structure */
9794  SCIP_CONS* cons, /**< knapsack constraint */
9795  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9796  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9797  )
9798 {
9799  SCIP_CONSDATA* consdata;
9800  SCIP_VAR** binvars;
9801  int nbinvars;
9802  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9803  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9804  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9805  int* zeroitems; /* item number in knapsack that is implied to zero */
9806  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9807  int zeroitemssize;
9808  int nzeroitems;
9809  SCIP_Bool* zeroiteminserted[2];
9810  SCIP_Bool memlimitreached;
9811  int nliftcands[2];
9812  SCIP_Bool* cliqueused;
9813  SCIP_Bool* itemremoved;
9814  SCIP_Longint maxcliqueweightsum;
9815  SCIP_VAR** addvars;
9816  SCIP_Longint* addweights;
9817  SCIP_Longint addweightsum;
9818  int nvars;
9819  int cliquenum;
9820  int naddvars;
9821  int val;
9822  int i;
9823 
9824  int* tmpindices;
9825  SCIP_Bool* tmpboolindices;
9826  int* tmpindices2;
9827  SCIP_Bool* tmpboolindices2;
9828  int* tmpindices3;
9829  SCIP_Bool* tmpboolindices3;
9830  int tmp;
9831  int tmp2;
9832  int tmp3;
9833  SCIP_CONSHDLR* conshdlr;
9834  SCIP_CONSHDLRDATA* conshdlrdata;
9835 
9836  assert(nchgcoefs != NULL);
9837  assert(!SCIPconsIsModifiable(cons));
9838 
9839  consdata = SCIPconsGetData(cons);
9840  assert(consdata != NULL);
9841  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9842  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9843  assert(consdata->nvars > 0);
9844  assert(consdata->merged);
9845 
9846  nvars = consdata->nvars;
9847 
9848  /* check if the knapsack has too many items/cliques for applying this costly method */
9849  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9850  return SCIP_OKAY;
9851 
9852  /* sort items, s.t. the heaviest one is in the first position */
9853  sortItems(consdata);
9854 
9855  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9856  return SCIP_OKAY;
9857 
9858  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9859  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9860  assert(nbinvars > 0);
9861  binvars = SCIPgetVars(scip);
9862 
9863  /* get conshdlrdata to use cleared memory */
9864  conshdlr = SCIPconsGetHdlr(cons);
9865  assert(conshdlr != NULL);
9866  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9867  assert(conshdlrdata != NULL);
9868 
9869  /* allocate temporary memory for the list of implied to zero variables */
9870  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9871  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9872  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9873 
9874  assert(conshdlrdata->ints1size > 0);
9875  assert(conshdlrdata->ints2size > 0);
9876  assert(conshdlrdata->longints1size > 0);
9877  assert(conshdlrdata->longints2size > 0);
9878 
9879  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9880  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9881  * transform all integers into their binary representation then it maybe happens
9882  */
9883  if( conshdlrdata->ints1size < nbinvars )
9884  {
9885  int oldsize = conshdlrdata->ints1size;
9886 
9887  conshdlrdata->ints1size = nbinvars;
9888  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9889  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9890  }
9891  if( conshdlrdata->ints2size < nbinvars )
9892  {
9893  int oldsize = conshdlrdata->ints2size;
9894 
9895  conshdlrdata->ints2size = nbinvars;
9896  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9897  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9898  }
9899  if( conshdlrdata->longints1size < nbinvars )
9900  {
9901  int oldsize = conshdlrdata->longints1size;
9902 
9903  conshdlrdata->longints1size = nbinvars;
9904  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9905  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9906  }
9907  if( conshdlrdata->longints2size < nbinvars )
9908  {
9909  int oldsize = conshdlrdata->longints2size;
9910 
9911  conshdlrdata->longints2size = nbinvars;
9912  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9913  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9914  }
9915 
9916  firstidxs[0] = conshdlrdata->ints1;
9917  firstidxs[1] = conshdlrdata->ints2;
9918  zeroweightsums[0] = conshdlrdata->longints1;
9919  zeroweightsums[1] = conshdlrdata->longints2;
9920 
9921  /* check for cleared arrays, all entries are zero */
9922 #ifndef NDEBUG
9923  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9924  {
9925  assert(firstidxs[0][tmp] == 0);
9926  assert(firstidxs[1][tmp] == 0);
9927  assert(zeroweightsums[0][tmp] == 0);
9928  assert(zeroweightsums[1][tmp] == 0);
9929  }
9930 #endif
9931 
9932  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9933  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9934 
9935  zeroitems[0] = -1; /* dummy element */
9936  nextidxs[0] = -1;
9937  nzeroitems = 1;
9938  nliftcands[0] = 0;
9939  nliftcands[1] = 0;
9940 
9941  assert(conshdlrdata->bools1size > 0);
9942  assert(conshdlrdata->bools2size > 0);
9943 
9944  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9945  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9946  * transform all integers into their binary representation then it maybe happens
9947  */
9948  if( conshdlrdata->bools1size < nbinvars )
9949  {
9950  int oldsize = conshdlrdata->bools1size;
9951 
9952  conshdlrdata->bools1size = nbinvars;
9953  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9954  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9955  }
9956  if( conshdlrdata->bools2size < nbinvars )
9957  {
9958  int oldsize = conshdlrdata->bools2size;
9959 
9960  conshdlrdata->bools2size = nbinvars;
9961  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9962  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9963  }
9964 
9965  zeroiteminserted[0] = conshdlrdata->bools1;
9966  zeroiteminserted[1] = conshdlrdata->bools2;
9967 
9968  /* check for cleared arrays, all entries are zero */
9969 #ifndef NDEBUG
9970  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9971  {
9972  assert(zeroiteminserted[0][tmp] == 0);
9973  assert(zeroiteminserted[1][tmp] == 0);
9974  }
9975 #endif
9976 
9977  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9978  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9979  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9980  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9981  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9982  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9983 
9984  tmp2 = 0;
9985  tmp3 = 0;
9986 
9987  memlimitreached = FALSE;
9988  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9989  {
9990  SCIP_CLIQUE** cliques;
9991  SCIP_VAR* var;
9992  SCIP_Longint weight;
9993  SCIP_Bool value;
9994  int varprobindex;
9995  int ncliques;
9996  int j;
9997 
9998  tmp = 0;
9999 
10000  /* get corresponding active problem variable */
10001  var = consdata->vars[i];
10002  weight = consdata->weights[i];
10003  value = TRUE;
10004  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10005  varprobindex = SCIPvarGetProbindex(var);
10006  assert(0 <= varprobindex && varprobindex < nbinvars);
10007 
10008  /* update the zeroweightsum */
10009  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10010  tmpboolindices3[tmp3] = !value;
10011  tmpindices3[tmp3] = varprobindex;
10012  ++tmp3;
10013 
10014  /* initialize the arrays of inserted zero items */
10015  /* first add the implications (~x == 1 -> x == 0) */
10016  {
10017  SCIP_Bool implvalue;
10018  int probindex;
10019 
10020  probindex = SCIPvarGetProbindex(var);
10021  assert(0 <= probindex && probindex < nbinvars);
10022 
10023  implvalue = !value;
10024 
10025  /* insert the item into the list of the implied variable/value */
10026  assert( !zeroiteminserted[implvalue][probindex] );
10027 
10028  if( firstidxs[implvalue][probindex] == 0 )
10029  {
10030  tmpboolindices2[tmp2] = implvalue;
10031  tmpindices2[tmp2] = probindex;
10032  ++tmp2;
10033  }
10034  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10035  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10036  &memlimitreached) );
10037  zeroiteminserted[implvalue][probindex] = TRUE;
10038  tmpboolindices[tmp] = implvalue;
10039  tmpindices[tmp] = probindex;
10040  ++tmp;
10041  }
10042 
10043  /* get the cliques where the knapsack item is member of with value 1 */
10044  ncliques = SCIPvarGetNCliques(var, value);
10045  cliques = SCIPvarGetCliques(var, value);
10046  for( j = 0; j < ncliques && !memlimitreached; ++j )
10047  {
10048  SCIP_VAR** cliquevars;
10049  SCIP_Bool* cliquevalues;
10050  int ncliquevars;
10051  int k;
10052 
10053  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10054 
10055  /* discard big cliques */
10056  if( ncliquevars > MAX_CLIQUELENGTH )
10057  continue;
10058 
10059  cliquevars = SCIPcliqueGetVars(cliques[j]);
10060  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10061 
10062  for( k = ncliquevars - 1; k >= 0; --k )
10063  {
10064  SCIP_Bool implvalue;
10065  int probindex;
10066 
10067  if( var == cliquevars[k] )
10068  continue;
10069 
10070  probindex = SCIPvarGetProbindex(cliquevars[k]);
10071  if( probindex == -1 )
10072  continue;
10073 
10074  assert(0 <= probindex && probindex < nbinvars);
10075  implvalue = cliquevalues[k];
10076 
10077  /* insert the item into the list of the clique variable/value */
10078  if( !zeroiteminserted[implvalue][probindex] )
10079  {
10080  if( firstidxs[implvalue][probindex] == 0 )
10081  {
10082  tmpboolindices2[tmp2] = implvalue;
10083  tmpindices2[tmp2] = probindex;
10084  ++tmp2;
10085  }
10086 
10087  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10088  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10089  &memlimitreached) );
10090  zeroiteminserted[implvalue][probindex] = TRUE;
10091  tmpboolindices[tmp] = implvalue;
10092  tmpindices[tmp] = probindex;
10093  ++tmp;
10094 
10095  if( memlimitreached )
10096  break;
10097  }
10098  }
10099  }
10100  /* clear zeroiteminserted */
10101  for( --tmp; tmp >= 0; --tmp)
10102  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10103  }
10104  SCIPfreeBufferArray(scip, &tmpboolindices);
10105 
10106  /* calculate the clique partition and the maximal sum of weights using the clique information */
10107  assert(consdata->sorted);
10108  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10109 
10110  assert(conshdlrdata->bools3size > 0);
10111 
10112  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10113  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10114  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10115  */
10116  if( conshdlrdata->bools3size < consdata->nvars )
10117  {
10118  int oldsize = conshdlrdata->bools3size;
10119 
10120  conshdlrdata->bools3size = consdata->nvars;;
10121  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10122  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10123  }
10124 
10125  cliqueused = conshdlrdata->bools3;
10126 
10127  /* check for cleared array, all entries are zero */
10128 #ifndef NDEBUG
10129  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10130  assert(cliqueused[tmp] == 0);
10131 #endif
10132 
10133  maxcliqueweightsum = 0;
10134  tmp = 0;
10135 
10136  /* calculates maximal weight of cliques */
10137  for( i = 0; i < consdata->nvars; ++i )
10138  {
10139  cliquenum = consdata->cliquepartition[i];
10140  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10141 
10142  if( !cliqueused[cliquenum] )
10143  {
10144  maxcliqueweightsum += consdata->weights[i];
10145  cliqueused[cliquenum] = TRUE;
10146  tmpindices[tmp] = cliquenum;
10147  ++tmp;
10148  }
10149  }
10150  /* clear cliqueused */
10151  for( --tmp; tmp >= 0; --tmp)
10152  cliqueused[tmp] = FALSE;
10153 
10154  assert(conshdlrdata->bools4size > 0);
10155 
10156  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10157  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10158  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10159  */
10160  if( conshdlrdata->bools4size < consdata->nvars )
10161  {
10162  int oldsize = conshdlrdata->bools4size;
10163 
10164  conshdlrdata->bools4size = consdata->nvars;
10165  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10166  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10167  }
10168 
10169  itemremoved = conshdlrdata->bools4;
10170 
10171  /* check for cleared array, all entries are zero */
10172 #ifndef NDEBUG
10173  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10174  assert(itemremoved[tmp] == 0);
10175 #endif
10176 
10177  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10178  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10179  * included in subsequent cliqueweightsum calculations)
10180  */
10181  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10182  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10183  naddvars = 0;
10184  addweightsum = 0;
10185  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10186  {
10187  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10188  {
10189  SCIP_Longint cliqueweightsum;
10190  int probindex;
10191  int idx;
10192  int j;
10193 
10194  tmp = 0;
10195 
10196  probindex = liftcands[val][i];
10197  assert(0 <= probindex && probindex < nbinvars);
10198 
10199  /* ignore empty zero lists and variables that cannot be lifted anyways */
10200  if( firstidxs[val][probindex] == 0
10201  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10202  continue;
10203 
10204  /* mark the items that are implied to zero by setting the current variable to the current value */
10205  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10206  {
10207  assert(0 < idx && idx < nzeroitems);
10208  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10209  itemremoved[zeroitems[idx]] = TRUE;
10210  }
10211 
10212  /* calculate the residual cliqueweight sum */
10213  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10214  for( j = 0; j < consdata->nvars; ++j )
10215  {
10216  cliquenum = consdata->cliquepartition[j];
10217  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10218  if( !itemremoved[j] )
10219  {
10220  if( !cliqueused[cliquenum] )
10221  {
10222  cliqueweightsum += consdata->weights[j];
10223  cliqueused[cliquenum] = TRUE;
10224  tmpindices[tmp] = cliquenum;
10225  ++tmp;
10226  }
10227 
10228  if( cliqueweightsum >= consdata->capacity )
10229  break;
10230  }
10231  }
10232 
10233  /* check if the weight of the variable/value can be increased */
10234  if( cliqueweightsum < consdata->capacity )
10235  {
10236  SCIP_VAR* var;
10237  SCIP_Longint weight;
10238 
10239  /* insert the variable (with value TRUE) in the list of additional items */
10240  assert(naddvars < 2*nbinvars);
10241  var = binvars[probindex];
10242  if( val == FALSE )
10243  {
10244  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10245  }
10246  weight = consdata->capacity - cliqueweightsum;
10247  addvars[naddvars] = var;
10248  addweights[naddvars] = weight;
10249  addweightsum += weight;
10250  naddvars++;
10251 
10252  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10253  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10254  }
10255 
10256  /* clear itemremoved */
10257  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10258  {
10259  assert(0 < idx && idx < nzeroitems);
10260  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10261  itemremoved[zeroitems[idx]] = FALSE;
10262  }
10263  /* clear cliqueused */
10264  for( --tmp; tmp >= 0; --tmp)
10265  cliqueused[tmpindices[tmp]] = FALSE;
10266  }
10267  }
10268 
10269  /* clear part of zeroweightsums */
10270  for( --tmp3; tmp3 >= 0; --tmp3)
10271  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10272 
10273  /* clear rest of zeroweightsums and firstidxs */
10274  for( --tmp2; tmp2 >= 0; --tmp2)
10275  {
10276  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10277  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10278  }
10279 
10280  /* add all additional item weights */
10281  for( i = 0; i < naddvars; ++i )
10282  {
10283  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10284  }
10285  *nchgcoefs += naddvars;
10286 
10287  if( naddvars > 0 )
10288  {
10289  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10290  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10291  }
10292 
10293  /* free temporary memory */
10294  SCIPfreeBufferArray(scip, &addweights);
10295  SCIPfreeBufferArray(scip, &addvars);
10296  SCIPfreeBufferArray(scip, &tmpindices);
10297  SCIPfreeBufferArray(scip, &tmpindices2);
10298  SCIPfreeBufferArray(scip, &tmpindices3);
10299  SCIPfreeBufferArray(scip, &tmpboolindices2);
10300  SCIPfreeBufferArray(scip, &tmpboolindices3);
10301  SCIPfreeBufferArray(scip, &nextidxs);
10302  SCIPfreeBufferArray(scip, &zeroitems);
10303  SCIPfreeBufferArray(scip, &liftcands[1]);
10304  SCIPfreeBufferArray(scip, &liftcands[0]);
10305 
10306  return SCIP_OKAY;
10307 }
10308 
10309 /** tightens item weights and capacity in presolving:
10310  * given a knapsack sum(wi*xi) <= capacity
10311  * (1) let weightsum := sum(wi)
10312  * if weightsum - wi < capacity:
10313  * - not using item i would make the knapsack constraint redundant
10314  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10315  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10316  * - change coefficients:
10317  * wi' := weightsum - capacity
10318  * capacity' := capacity - (wi - wi')
10319  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10320  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10321  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10322  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10323  * can be multiple times the same weight, this can be improved
10324  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10325  * weight, to capacity - lastmininmalweightsum, e.g. :
10326  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10327  * -> minimal weightsums: 5, 5, 10, 10
10328  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10329  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10330  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10331  * (3) let W(C) be the maximal weight of clique C,
10332  * cliqueweightsum := sum(W(C))
10333  * if cliqueweightsum - W(C) < capacity:
10334  * - not using any item of C would make the knapsack constraint redundant
10335  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10336  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10337  * - change coefficients:
10338  * delta := capacity - (cliqueweightsum - W(C))
10339  * wi' := max(wi - delta, 0)
10340  * capacity' := capacity - delta
10341  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10342  * introduce infeasible solutions.
10343  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10344  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10345  * if cliqueweightsum(xi == v) < capacity:
10346  * - fixing variable xi to v would make the knapsack constraint redundant
10347  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10348  * redundancy effect:
10349  * wi' := capacity - cliqueweightsum(xi == v)
10350  * This rule can also be applied to binary variables not in the knapsack!
10351  * (5) if min{w} + wi > capacity:
10352  * - using item i would force to fix other items to zero
10353  * - wi can be increased to the capacity
10354  */
10355 static
10357  SCIP* scip, /**< SCIP data structure */
10358  SCIP_CONS* cons, /**< knapsack constraint */
10359  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10360  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10361  int* nchgsides, /**< pointer to count number of side changes */
10362  int* naddconss, /**< pointer to count number of added constraints */
10363  int* ndelconss, /**< pointer to count number of deleted constraints */
10364  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10365  )
10366 {
10367  SCIP_CONSHDLRDATA* conshdlrdata;
10368  SCIP_CONSDATA* consdata;
10369  SCIP_Longint* weights;
10370  SCIP_Longint sumcoef;
10371  SCIP_Longint capacity;
10372  SCIP_Longint newweight;
10373  SCIP_Longint maxweight;
10374  SCIP_Longint minweight;
10375  SCIP_Bool sumcoefcase = FALSE;
10376  int startpos;
10377  int backpos;
10378  int nvars;
10379  int pos;
10380  int k;
10381  int i;
10382 
10383  assert(nchgcoefs != NULL);
10384  assert(nchgsides != NULL);
10385  assert(!SCIPconsIsModifiable(cons));
10386 
10387  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10388  assert(conshdlrdata != NULL);
10389 
10390  consdata = SCIPconsGetData(cons);
10391  assert(consdata != NULL);
10392  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10393  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10394  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10395  assert(consdata->nvars > 0);
10396 
10397  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10398  if( *cutoff )
10399  return SCIP_OKAY;
10400 
10401  /* apply rule (1) */
10402  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10403  {
10404  do
10405  {
10406  assert(consdata->merged);
10407 
10408  /* sort items, s.t. the heaviest one is in the first position */
10409  sortItems(consdata);
10410 
10411  for( i = 0; i < consdata->nvars; ++i )
10412  {
10413  SCIP_Longint weight;
10414 
10415  weight = consdata->weights[i];
10416  if( consdata->weightsum - weight < consdata->capacity )
10417  {
10418  newweight = consdata->weightsum - consdata->capacity;
10419  consdataChgWeight(consdata, i, newweight);
10420  consdata->capacity -= (weight - newweight);
10421  (*nchgcoefs)++;
10422  (*nchgsides)++;
10423  assert(!consdata->sorted);
10424  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",
10425  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10426  consdata->capacity + (weight-newweight), consdata->capacity);
10427  }
10428  else
10429  break;
10430  }
10431  }
10432  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10433  }
10434 
10435  /* check for redundancy */
10436  if( consdata->weightsum <= consdata->capacity )
10437  return SCIP_OKAY;
10438 
10439  pos = 0;
10440  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10441  ++pos;
10442 
10443  sumcoef = 0;
10444  weights = consdata->weights;
10445  nvars = consdata->nvars;
10446  capacity = consdata->capacity;
10447 
10448  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10449  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10450  {
10451  /* further reductions using the next possible coefficient sum
10452  *
10453  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10454  */
10455  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10456  for( k = 0; k < 4; ++k )
10457  {
10458  newweight = capacity - sumcoef;
10459 
10460  /* determine next minimal coefficient sum */
10461  switch( k )
10462  {
10463  case 0:
10464  sumcoef = weights[nvars - 1];
10465  backpos = nvars - 1;
10466  break;
10467  case 1:
10468  sumcoef = weights[nvars - 2];
10469  backpos = nvars - 2;
10470  break;
10471  case 2:
10472  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10473  {
10474  sumcoefcase = TRUE;
10475  sumcoef = weights[nvars - 3];
10476  backpos = nvars - 3;
10477  }
10478  else
10479  {
10480  sumcoefcase = FALSE;
10481  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10482  backpos = nvars - 2;
10483  }
10484  break;
10485  default:
10486  assert(k == 3);
10487  if( sumcoefcase )
10488  {
10489  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10490  {
10491  sumcoef = weights[nvars - 4];
10492  backpos = nvars - 4;
10493  }
10494  else
10495  {
10496  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10497  backpos = nvars - 2;
10498  }
10499  }
10500  else
10501  {
10502  sumcoef = weights[nvars - 3];
10503  backpos = nvars - 3;
10504  }
10505  break;
10506  }
10507 
10508  if( backpos <= pos )
10509  break;
10510 
10511  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10512  maxweight = weights[pos];
10513  startpos = pos;
10514  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10515  {
10516  assert(newweight > weights[pos]);
10517 
10518  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10519  SCIPconsGetName(cons), maxweight, newweight);
10520 
10521  consdataChgWeight(consdata, pos, newweight);
10522 
10523  ++pos;
10524  assert(pos < nvars);
10525 
10526  maxweight = weights[pos];
10527 
10528  if( backpos <= pos )
10529  break;
10530  }
10531  (*nchgcoefs) += (pos - startpos);
10532 
10533  /* skip unchangable weights */
10534  while( pos < nvars && weights[pos] + sumcoef == capacity )
10535  ++pos;
10536 
10537  /* check special case were there is only one weight left to tighten
10538  *
10539  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10540  *
10541  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10542  *
10543  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10544  */
10545  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10546  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10547  {
10548  newweight = capacity - sumcoef;
10549  assert(newweight > weights[pos]);
10550 
10551  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10552  SCIPconsGetName(cons), maxweight, newweight);
10553 
10554  consdataChgWeight(consdata, pos, newweight);
10555 
10556  break;
10557  }
10558 
10559  if( backpos <= pos )
10560  break;
10561  }
10562  }
10563 
10564  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10565  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10566  {
10567  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10568  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10569  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10570  {
10571  SCIP_VAR** clqvars;
10572  SCIP_CONS* cliquecons;
10573  char name[SCIP_MAXSTRLEN];
10574  int* clqpart;
10575  int nclqvars;
10576  int nclq;
10577  int len;
10578  int c;
10579  int w;
10580 
10581  assert(!SCIPconsIsDeleted(cons));
10582 
10583  if( pos == consdata->nvars )
10584  {
10585  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10586 
10587  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10591  SCIPconsIsStickingAtNode(cons)) );
10592 
10593  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10594  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10595  ++(*naddconss);
10596 
10597  /* delete old constraint */
10598  SCIP_CALL( SCIPdelCons(scip, cons) );
10599  ++(*ndelconss);
10600 
10601  return SCIP_OKAY;
10602  }
10603 
10604  len = consdata->nvars - pos;
10605 
10606  /* allocate temporary memory */
10607  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10608 
10609  /* calculate clique partition */
10610  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10611  assert(nclq <= len);
10612 
10613 #ifndef NDEBUG
10614  /* clique numbers must be at least as high as the index */
10615  for( w = 0; w < nclq; ++w )
10616  assert(clqpart[w] <= w);
10617 #endif
10618 
10619  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10620 
10621  /* allocate temporary memory */
10622  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10623 
10624  /* copy corresponding variables with big coefficients */
10625  for( w = pos - 1; w >= 0; --w )
10626  clqvars[w] = consdata->vars[w];
10627 
10628  /* create for each clique a set-packing constraint */
10629  for( c = 0; c < nclq; ++c )
10630  {
10631  nclqvars = pos;
10632 
10633  for( w = c; w < len; ++w )
10634  {
10635  if( clqpart[w] == c )
10636  {
10637  assert(nclqvars < pos + len - nclq + 1);
10638  clqvars[nclqvars] = consdata->vars[w + pos];
10639  ++nclqvars;
10640  }
10641  }
10642 
10643  assert(nclqvars > 1);
10644 
10645  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10646  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10650  SCIPconsIsStickingAtNode(cons)) );
10651  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10652  SCIPdebugPrintCons(scip, cliquecons, NULL);
10653  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10654  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10655  ++(*naddconss);
10656  }
10657 
10658  /* delete old constraint */
10659  SCIP_CALL( SCIPdelCons(scip, cons) );
10660  ++(*ndelconss);
10661 
10662  SCIPfreeBufferArray(scip, &clqvars);
10663  SCIPfreeBufferArray(scip, &clqpart);
10664 
10665  return SCIP_OKAY;
10666  }
10667  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10668  {
10669  SCIP_Longint* maxcliqueweights;
10670  SCIP_Longint* newweightvals;
10671  int* newweightidxs;
10672  SCIP_Longint cliqueweightsum;
10673 
10674  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10675  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10676  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10677 
10678  /* repeat as long as changes have been applied */
10679  do
10680  {
10681  int ncliques;
10682  int cliquenum;
10683  SCIP_Bool zeroweights;
10684 
10685  assert(consdata->merged);
10686 
10687  /* sort items, s.t. the heaviest one is in the first position */
10688  sortItems(consdata);
10689 
10690  /* calculate a clique partition */
10691  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10692 
10693  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10694  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10695  break;
10696 
10697  /* calculate the maximal weight of the cliques and store the clique type */
10698  cliqueweightsum = 0;
10699  ncliques = 0;
10700 
10701  for( i = 0; i < consdata->nvars; ++i )
10702  {
10703  SCIP_Longint weight;
10704 
10705  cliquenum = consdata->cliquepartition[i];
10706  assert(0 <= cliquenum && cliquenum <= ncliques);
10707 
10708  weight = consdata->weights[i];
10709  assert(weight > 0);
10710 
10711  if( cliquenum == ncliques )
10712  {
10713  maxcliqueweights[ncliques] = weight;
10714  cliqueweightsum += weight;
10715  ++ncliques;
10716  }
10717 
10718  assert(maxcliqueweights[cliquenum] >= weight);
10719  }
10720 
10721  /* apply rule on every clique */
10722  zeroweights = FALSE;
10723  for( i = 0; i < ncliques; ++i )
10724  {
10725  SCIP_Longint delta;
10726 
10727  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10728  if( delta > 0 )
10729  {
10730  SCIP_Longint newcapacity;
10731 #ifndef NDEBUG
10732  SCIP_Longint newmincliqueweight;
10733 #endif
10734  SCIP_Longint newminweightsuminclique;
10735  SCIP_Bool forceclique;
10736  int nnewweights;
10737  int j;
10738 
10739  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",
10740  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10741  newcapacity = consdata->capacity - delta;
10742  forceclique = FALSE;
10743  nnewweights = 0;
10744 #ifndef NDEBUG
10745  newmincliqueweight = newcapacity + 1;
10746  for( j = 0; j < i; ++j )
10747  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10748 #endif
10749  for( j = i; j < consdata->nvars; ++j )
10750  {
10751  if( consdata->cliquepartition[j] == i )
10752  {
10753  newweight = consdata->weights[j] - delta;
10754  newweight = MAX(newweight, 0);
10755 
10756  /* cache the new weight */
10757  assert(nnewweights < consdata->nvars);
10758  newweightvals[nnewweights] = newweight;
10759  newweightidxs[nnewweights] = j;
10760  nnewweights++;
10761 
10762 #ifndef NDEBUG
10763  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10764  newmincliqueweight = newweight;
10765 #endif
10766  }
10767  }
10768 
10769  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10770  if( nnewweights > 1 )
10771  {
10772 #ifndef NDEBUG
10773  j = newweightidxs[nnewweights - 2];
10774  assert(0 <= j && j < consdata->nvars);
10775  assert(consdata->cliquepartition[j] == i);
10776  j = newweightidxs[nnewweights - 1];
10777  assert(0 <= j && j < consdata->nvars);
10778  assert(consdata->cliquepartition[j] == i);
10779 #endif
10780 
10781  newminweightsuminclique = newweightvals[nnewweights - 2];
10782  newminweightsuminclique += newweightvals[nnewweights - 1];
10783 
10784  /* check if these new two minimal weights both fit into the knapsack;
10785  * if this is true, we have to add a clique constraint in order to enforce the clique
10786  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10787  * reduction might be infeasible, i.e., allows additional solutions)
10788  */
10789  if( newminweightsuminclique <= newcapacity )
10790  forceclique = TRUE;
10791  }
10792 
10793  /* check if we really want to apply the change */
10794  if( conshdlrdata->disaggregation || !forceclique )
10795  {
10796  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10797  consdata->capacity, newcapacity, forceclique);
10798  consdata->capacity = newcapacity;
10799  (*nchgsides)++;
10800 
10801  for( k = 0; k < nnewweights; ++k )
10802  {
10803  j = newweightidxs[k];
10804  assert(0 <= j && j < consdata->nvars);
10805  assert(consdata->cliquepartition[j] == i);
10806 
10807  /* apply the weight change */
10808  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10809  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10810  consdataChgWeight(consdata, j, newweightvals[k]);
10811  (*nchgcoefs)++;
10812  assert(!consdata->sorted);
10813  zeroweights = zeroweights || (newweightvals[k] == 0);
10814  }
10815  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10816  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10817  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10818  * knapsack constraint
10819  */
10820  if( forceclique )
10821  {
10822  SCIP_CONS* cliquecons;
10823  char name[SCIP_MAXSTRLEN];
10824  SCIP_VAR** cliquevars;
10825 
10826  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10827  for( k = 0; k < nnewweights; ++k )
10828  cliquevars[k] = consdata->vars[newweightidxs[k]];
10829 
10830  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10831  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10835  SCIPconsIsStickingAtNode(cons)) );
10836  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10837  SCIPdebugPrintCons(scip, cliquecons, NULL);
10838  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10839  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10840  SCIPfreeBufferArray(scip, &cliquevars);
10841  (*naddconss)++;
10842  }
10843  }
10844  }
10845  }
10846  if( zeroweights )
10847  {
10848  SCIP_CALL( removeZeroWeights(scip, cons) );
10849  }
10850  }
10851  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10852 
10853  /* free temporary memory */
10854  SCIPfreeBufferArray(scip, &newweightidxs);
10855  SCIPfreeBufferArray(scip, &newweightvals);
10856  SCIPfreeBufferArray(scip, &maxcliqueweights);
10857 
10858  /* check for redundancy */
10859  if( consdata->weightsum <= consdata->capacity )
10860  return SCIP_OKAY;
10861  }
10862  }
10863 
10864  /* apply rule (3) */
10865  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10866  {
10867  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10868  }
10869 
10870  /* check for redundancy */
10871  if( consdata->weightsum <= consdata->capacity )
10872  return SCIP_OKAY;
10873 
10874  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10875  {
10876  /* apply rule (4) (all but smallest weight) */
10877  assert(consdata->merged);
10878  sortItems(consdata);
10879  minweight = consdata->weights[consdata->nvars-1];
10880  for( i = 0; i < consdata->nvars-1; ++i )
10881  {
10882  SCIP_Longint weight;
10883 
10884  weight = consdata->weights[i];
10885  assert(weight >= minweight);
10886  if( minweight + weight > consdata->capacity )
10887  {
10888  if( weight < consdata->capacity )
10889  {
10890  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10891  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10892  assert(consdata->sorted);
10893  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10894  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10895  consdata->sorted = TRUE;
10896  (*nchgcoefs)++;
10897  }
10898  }
10899  else
10900  break;
10901  }
10902 
10903  /* apply rule (5) (smallest weight) */
10904  if( consdata->nvars >= 2 )
10905  {
10906  SCIP_Longint weight;
10907 
10908  minweight = consdata->weights[consdata->nvars-2];
10909  weight = consdata->weights[consdata->nvars-1];
10910  assert(minweight >= weight);
10911  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10912  {
10913  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10914  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10915  assert(consdata->sorted);
10916  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10917  assert(minweight >= consdata->weights[consdata->nvars-1]);
10918  consdata->sorted = TRUE;
10919  (*nchgcoefs)++;
10920  }
10921  }
10922  }
10923 
10924  return SCIP_OKAY;
10925 }
10926 
10927 
10928 #ifdef SCIP_DEBUG
10929 static
10930 void printClique(
10931  SCIP_VAR** cliquevars,
10932  int ncliquevars
10933  )
10934 {
10935  int b;
10936  SCIPdebugMessage("adding new Clique: ");
10937  for( b = 0; b < ncliquevars; ++b )
10938  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10939  SCIPdebugPrintf("\n");
10940 }
10941 #endif
10942 
10943 /** adds negated cliques of the knapsack constraint to the global clique table */
10944 static
10946  SCIP*const scip, /**< SCIP data structure */
10947  SCIP_CONS*const cons, /**< knapsack constraint */
10948  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10949  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10950  )
10951 {
10952  SCIP_CONSDATA* consdata;
10953  SCIP_CONSHDLRDATA* conshdlrdata;
10954  SCIP_VAR** poscliquevars;
10955  SCIP_VAR** cliquevars;
10956  SCIP_Longint* maxweights;
10957  SCIP_Longint* gainweights;
10958  int* gaincliquepartition;
10959  SCIP_Bool* cliqueused;
10960  SCIP_Longint minactduetonegcliques;
10961  SCIP_Longint freecapacity;
10962  SCIP_Longint lastweight;
10963  SCIP_Longint beforelastweight;
10964  int nposcliquevars;
10965  int ncliquevars;
10966  int nvars;
10967  int nnegcliques;
10968  int lastcliqueused;
10969  int thisnbdchgs;
10970  int v;
10971  int w;
10972 
10973  assert(scip != NULL);
10974  assert(cons != NULL);
10975  assert(cutoff != NULL);
10976  assert(nbdchgs != NULL);
10977 
10978  *cutoff = FALSE;
10979 
10980  consdata = SCIPconsGetData(cons);
10981  assert(consdata != NULL);
10982 
10983  nvars = consdata->nvars;
10984 
10985  /* check whether the cliques have already been added */
10986  if( consdata->cliquesadded || nvars == 0 )
10987  return SCIP_OKAY;
10988 
10989  /* make sure, the items are merged */
10990  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10991  if( *cutoff )
10992  return SCIP_OKAY;
10993 
10994  /* make sure, items are sorted by non-increasing weight */
10995  sortItems(consdata);
10996 
10997  assert(consdata->merged);
10998 
10999  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11000  assert(conshdlrdata != NULL);
11001 
11002  /* calculate a clique partition */
11003  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11004  nnegcliques = consdata->nnegcliques;
11005 
11006  /* if we have no negated cliques, stop */
11007  if( nnegcliques == nvars )
11008  return SCIP_OKAY;
11009 
11010  /* get temporary memory */
11011  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11012  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11013  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11014  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11015  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11016  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11017 
11018  nnegcliques = 0;
11019  minactduetonegcliques = 0;
11020 
11021  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11022  for( v = 0; v < nvars; ++v )
11023  {
11024  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11025  assert(consdata->weights[v] > 0);
11026 
11027  if( consdata->negcliquepartition[v] == nnegcliques )
11028  {
11029  nnegcliques++;
11030  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11031  }
11032  else
11033  minactduetonegcliques += consdata->weights[v];
11034  }
11035 
11036  nposcliquevars = 0;
11037 
11038  /* add cliques, using negated cliques information */
11039  if( minactduetonegcliques > 0 )
11040  {
11041  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11042  freecapacity = consdata->capacity - minactduetonegcliques;
11043 
11044  SCIPdebugPrintCons(scip, cons, NULL);
11045  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",
11046  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11047 
11048  /* calculate possible gain by switching chosen items in negated cliques */
11049  for( v = 0; v < nvars; ++v )
11050  {
11051  if( !cliqueused[consdata->negcliquepartition[v]] )
11052  {
11053  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11054  for( w = v + 1; w < nvars; ++w )
11055  {
11056  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11057  * weight[w] (which are both in a negated clique) */
11058  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11059  && consdata->weights[v] > consdata->weights[w] )
11060  {
11061  poscliquevars[nposcliquevars] = consdata->vars[w];
11062  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11063  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11064  ++nposcliquevars;
11065  }
11066  }
11067  }
11068  }
11069 
11070  /* try to create negated cliques */
11071  if( nposcliquevars > 0 )
11072  {
11073  /* sort possible gain per substitution of the clique members */
11074  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11075 
11076  for( v = 0; v < nposcliquevars; ++v )
11077  {
11078  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11079  ncliquevars = 1;
11080  lastweight = gainweights[v];
11081  beforelastweight = -1;
11082  lastcliqueused = gaincliquepartition[v];
11083  /* clear cliqueused to get an unused array */
11084  BMSclearMemoryArray(cliqueused, nnegcliques);
11085  cliqueused[gaincliquepartition[v]] = TRUE;
11086 
11087  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11088  * in the same negated clique and by taking two of them would exceed the free capacity */
11089  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11090  {
11091  beforelastweight = lastweight;
11092  lastweight = gainweights[w];
11093  lastcliqueused = gaincliquepartition[w];
11094  cliqueused[gaincliquepartition[w]] = TRUE;
11095  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11096  ++ncliquevars;
11097  }
11098 
11099  if( ncliquevars > 1 )
11100  {
11101  SCIPdebug( printClique(cliquevars, ncliquevars) );
11102  assert(beforelastweight > 0);
11103  /* add the clique to the clique table */
11104  /* this really happens, e.g., on enigma.mps from the short test set */
11105  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11106  if( *cutoff )
11107  goto TERMINATE;
11108  *nbdchgs += thisnbdchgs;
11109 
11110  /* reset last used clique to get slightly different cliques */
11111  cliqueused[lastcliqueused] = FALSE;
11112 
11113  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11114  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11115  {
11116  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11117  SCIPdebug( printClique(cliquevars, ncliquevars) );
11118  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11119  if( *cutoff )
11120  goto TERMINATE;
11121  *nbdchgs += thisnbdchgs;
11122  }
11123  }
11124  }
11125  }
11126  }
11127 
11128  TERMINATE:
11129  /* free temporary memory */
11130  SCIPfreeBufferArray(scip, &cliqueused);
11131  SCIPfreeBufferArray(scip, &maxweights);
11132  SCIPfreeBufferArray(scip, &gaincliquepartition);
11133  SCIPfreeBufferArray(scip, &gainweights);
11134  SCIPfreeBufferArray(scip, &cliquevars);
11135  SCIPfreeBufferArray(scip, &poscliquevars);
11136 
11137  return SCIP_OKAY;
11138 }
11139 
11140 /** greedy clique detection by considering weights and capacity
11141  *
11142  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11143  * 1) neighboring items which exceed the capacity together => one clique
11144  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11145  */
11146 static
11148  SCIP*const scip, /**< SCIP data structure */
11149  SCIP_VAR** items, /**< array of variable items */
11150  SCIP_Longint* weights, /**< weights of the items */
11151  int nitems, /**< the number of items */
11152  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11153  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11154  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11155  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11156  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11157  )
11158 {
11159  SCIP_Longint lastweight;
11160  int ncliquevars;
11161  int i;
11162  int thisnbdchgs;
11163 
11164  if( nitems <= 1 )
11165  return SCIP_OKAY;
11166 
11167  /* sort possible gain per substitution of the clique members */
11168  if( ! sorteditems )
11169  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11170 
11171  ncliquevars = 1;
11172  lastweight = weights[0];
11173 
11174  /* taking these two weights together violates the knapsack => include into clique */
11175  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11176  {
11177  lastweight = weights[i];
11178  ++ncliquevars;
11179  }
11180 
11181  if( ncliquevars > 1 )
11182  {
11183  SCIP_Longint compareweight;
11184  SCIP_VAR** cliquevars;
11185  int compareweightidx;
11186  int minclqsize;
11187  int nnzadded;
11188 
11189  /* add the clique to the clique table */
11190  SCIPdebug( printClique(items, ncliquevars) );
11191  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11192 
11193  if( *cutoff )
11194  return SCIP_OKAY;
11195 
11196  *nbdchgs += thisnbdchgs;
11197  nnzadded = ncliquevars;
11198 
11199  /* 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)*/
11200  if( ncliquevars == nitems )
11201  return SCIP_OKAY;
11202 
11203  /* copy items in order into buffer array and deduce more cliques */
11204  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11205 
11206  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11207  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11208  compareweightidx = ncliquevars - 2;
11209  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11210 
11211  /* determine minimum clique size for the following loop */
11212  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11213  minclqsize = MAX(minclqsize, 2);
11214 
11215  /* loop over the remaining variables and the larger items of the first clique until we
11216  * find another clique or reach the size limit */
11217  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11218  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11219  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11220  )
11221  {
11222  compareweight = weights[compareweightidx];
11223  assert(compareweight > 0);
11224 
11225  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11226  if( compareweight + weights[i] > capacity )
11227  {
11228  assert(compareweightidx == ncliquevars -2);
11229  cliquevars[ncliquevars - 1] = items[i];
11230  SCIPdebug( printClique(cliquevars, ncliquevars) );
11231  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11232 
11233  nnzadded += ncliquevars;
11234 
11235  /* stop when there is a cutoff */
11236  if( ! (*cutoff) )
11237  *nbdchgs += thisnbdchgs;
11238 
11239  /* go to next smaller item */
11240  ++i;
11241  }
11242  else
11243  {
11244  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11245  compareweightidx--;
11246  ncliquevars --;
11247  }
11248  }
11249 
11250  SCIPfreeBufferArray(scip, &cliquevars);
11251  }
11252 
11253  return SCIP_OKAY;
11254 }
11255 
11256 /** adds cliques of the knapsack constraint to the global clique table */
11257 static
11259  SCIP*const scip, /**< SCIP data structure */
11260  SCIP_CONS*const cons, /**< knapsack constraint */
11261  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11262  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11263  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11264  )
11265 {
11266  SCIP_CONSDATA* consdata;
11267  SCIP_CONSHDLRDATA* conshdlrdata;
11268  int i;
11269  SCIP_Longint minactduetonegcliques;
11270  SCIP_Longint freecapacity;
11271  int nnegcliques;
11272  int cliquenum;
11273  SCIP_VAR** poscliquevars;
11274  SCIP_Longint* gainweights;
11275  int nposcliquevars;
11276  SCIP_Longint* secondmaxweights;
11277  int nvars;
11278 
11279  assert(scip != NULL);
11280  assert(cons != NULL);
11281  assert(cutoff != NULL);
11282  assert(nbdchgs != NULL);
11283 
11284  *cutoff = FALSE;
11285 
11286  consdata = SCIPconsGetData(cons);
11287  assert(consdata != NULL);
11288 
11289  nvars = consdata->nvars;
11290 
11291  /* check whether the cliques have already been added */
11292  if( consdata->cliquesadded || nvars == 0 )
11293  return SCIP_OKAY;
11294 
11295  /* make sure, the items are merged */
11296  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11297  if( *cutoff )
11298  return SCIP_OKAY;
11299 
11300  /* make sure, the items are sorted by non-increasing weight */
11301  sortItems(consdata);
11302 
11303  assert(consdata->merged);
11304 
11305  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11306  assert(conshdlrdata != NULL);
11307 
11308  /* calculate a clique partition */
11309  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11310  nnegcliques = consdata->nnegcliques;
11311  assert(nnegcliques <= nvars);
11312 
11313  /* get temporary memory */
11314  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11315  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11316  BMSclearMemoryArray(gainweights, nvars);
11317  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11318  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11319 
11320  minactduetonegcliques = 0;
11321 
11322  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11323  if( nnegcliques < nvars )
11324  {
11325  nnegcliques = 0;
11326 
11327  for( i = 0; i < nvars; ++i )
11328  {
11329  SCIP_Longint weight;
11330 
11331  cliquenum = consdata->negcliquepartition[i];
11332  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11333 
11334  weight = consdata->weights[i];
11335  assert(weight > 0);
11336 
11337  if( cliquenum == nnegcliques )
11338  nnegcliques++;
11339  else
11340  {
11341  minactduetonegcliques += weight;
11342  if( secondmaxweights[cliquenum] == 0 )
11343  secondmaxweights[cliquenum] = weight;
11344  }
11345  }
11346  }
11347 
11348  /* add cliques, using negated cliques information */
11349  if( minactduetonegcliques > 0 )
11350  {
11351  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11352  freecapacity = consdata->capacity - minactduetonegcliques;
11353 
11354  SCIPdebugPrintCons(scip, cons, NULL);
11355  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",
11356  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11357 
11358  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11359  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11360 
11361  if( *cutoff )
11362  goto TERMINATE;
11363 
11364  nposcliquevars = 0;
11365 
11366  for( i = nvars - 1; i >= 0; --i )
11367  {
11368  /* if we would take the biggest weight instead of the second biggest */
11369  cliquenum = consdata->negcliquepartition[i];
11370  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11371  {
11372  poscliquevars[nposcliquevars] = consdata->vars[i];
11373  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11374  ++nposcliquevars;
11375  }
11376  }
11377 
11378  /* use the gain weights and free capacity to derive greedily cliques */
11379  if( nposcliquevars > 1 )
11380  {
11381  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11382 
11383  if( *cutoff )
11384  goto TERMINATE;
11385  }
11386  }
11387 
11388  /* build cliques by using the items with the maximal weights */
11389  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11390 
11391  TERMINATE:
11392  /* free temporary memory and mark the constraint */
11393  SCIPfreeBufferArray(scip, &secondmaxweights);
11394  SCIPfreeBufferArray(scip, &gainweights);
11395  SCIPfreeBufferArray(scip, &poscliquevars);
11396  consdata->cliquesadded = TRUE;
11397 
11398  return SCIP_OKAY;
11399 }
11400 
11401 
11402 /** gets the key of the given element */
11403 static
11404 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11405 { /*lint --e{715}*/
11406  /* the key is the element itself */
11407  return elem;
11408 }
11409 
11410 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11411  * same coefficients
11412  */
11413 static
11414 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11415 {
11416 #ifndef NDEBUG
11417  SCIP* scip;
11418 #endif
11419  SCIP_CONSDATA* consdata1;
11420  SCIP_CONSDATA* consdata2;
11421  int i;
11423  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11424  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11425  assert(consdata1->sorted);
11426  assert(consdata2->sorted);
11427 #ifndef NDEBUG
11428  scip = (SCIP*)userptr;
11429  assert(scip != NULL);
11430 #endif
11431 
11432  /* checks trivial case */
11433  if( consdata1->nvars != consdata2->nvars )
11434  return FALSE;
11435 
11436  for( i = consdata1->nvars - 1; i >= 0; --i )
11437  {
11438  /* tests if variables are equal */
11439  if( consdata1->vars[i] != consdata2->vars[i] )
11440  {
11441  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11442  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11443  return FALSE;
11444  }
11445  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11446 
11447  /* tests if weights are equal too */
11448  if( consdata1->weights[i] != consdata2->weights[i] )
11449  return FALSE;
11450  }
11451 
11452  return TRUE;
11453 }
11454 
11455 /** returns the hash value of the key */
11456 static
11457 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11458 {
11459 #ifndef NDEBUG
11460  SCIP* scip;
11461 #endif
11462  SCIP_CONSDATA* consdata;
11463  uint64_t firstweight;
11464  int minidx;
11465  int mididx;
11466  int maxidx;
11467 
11468  consdata = SCIPconsGetData((SCIP_CONS*)key);
11469  assert(consdata != NULL);
11470  assert(consdata->nvars > 0);
11471 
11472 #ifndef NDEBUG
11473  scip = (SCIP*)userptr;
11474  assert(scip != NULL);
11475 #endif
11476 
11477  /* sorts the constraints */
11478  sortItems(consdata);
11479 
11480  minidx = SCIPvarGetIndex(consdata->vars[0]);
11481  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11482  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11483  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11484 
11485  /* hash value depends on vectors of variable indices */
11486  firstweight = (uint64_t)consdata->weights[0];
11487  return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11488 }
11489 
11490 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11491  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11492  */
11493 static
11495  SCIP* scip, /**< SCIP data structure */
11496  BMS_BLKMEM* blkmem, /**< block memory */
11497  SCIP_CONS** conss, /**< constraint set */
11498  int nconss, /**< number of constraints in constraint set */
11499  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11500  int* ndelconss /**< pointer to count number of deleted constraints */
11501  )
11503  SCIP_HASHTABLE* hashtable;
11504  int hashtablesize;
11505  int c;
11506 
11507  assert(scip != NULL);
11508  assert(blkmem != NULL);
11509  assert(conss != NULL);
11510  assert(ndelconss != NULL);
11511 
11512  /* create a hash table for the constraint set */
11513  hashtablesize = nconss;
11514  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11515  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11516  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11517 
11518  /* check all constraints in the given set for redundancy */
11519  for( c = nconss - 1; c >= 0; --c )
11520  {
11521  SCIP_CONS* cons0;
11522  SCIP_CONS* cons1;
11523  SCIP_CONSDATA* consdata0;
11524 
11525  cons0 = conss[c];
11526 
11527  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11528  continue;
11529 
11530  consdata0 = SCIPconsGetData(cons0);
11531  assert(consdata0 != NULL);
11532  if( consdata0->nvars == 0 )
11533  {
11534  if( consdata0->capacity < 0 )
11535  {
11536  *cutoff = TRUE;
11537  goto TERMINATE;
11538  }
11539  else
11540  {
11541  SCIP_CALL( SCIPdelCons(scip, cons0) );
11542  ++(*ndelconss);
11543  continue;
11544  }
11545  }
11546 
11547  /* get constraint from current hash table with same variables and same weights as cons0 */
11548  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11549 
11550  if( cons1 != NULL )
11551  {
11552  SCIP_CONS* consstay;
11553  SCIP_CONS* consdel;
11554  SCIP_CONSDATA* consdata1;
11555 
11556  assert(SCIPconsIsActive(cons1));
11557  assert(!SCIPconsIsModifiable(cons1));
11558 
11559  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11560  * delete old constraints afterwards
11561  */
11562  consdata1 = SCIPconsGetData(cons1);
11563 
11564  assert(consdata1 != NULL);
11565  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11566 
11567  assert(consdata0->sorted && consdata1->sorted);
11568  assert(consdata0->vars[0] == consdata1->vars[0]);
11569  assert(consdata0->weights[0] == consdata1->weights[0]);
11570 
11571  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11572  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11573 
11574  /* check which constraint has to stay; */
11575  if( consdata0->capacity < consdata1->capacity )
11576  {
11577  consstay = cons0;
11578  consdel = cons1;
11579 
11580  /* exchange consdel with consstay in hashtable */
11581  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11582  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11583  }
11584  else
11585  {
11586  consstay = cons1;
11587  consdel = cons0;
11588  }
11589 
11590  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11591  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11592 
11593  /* delete consdel */
11594  SCIP_CALL( SCIPdelCons(scip, consdel) );
11595  ++(*ndelconss);
11596 
11597  assert(SCIPconsIsActive(consstay));
11598  }
11599  else
11600  {
11601  /* no such constraint in current hash table: insert cons0 into hash table */
11602  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11603  }
11604  }
11605 
11606  TERMINATE:
11607  /* free hash table */
11608  SCIPhashtableFree(&hashtable);
11609 
11610  return SCIP_OKAY;
11611 }
11612 
11613 
11614 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11615  * and removes or changes constraint accordingly
11616  */
11617 static
11619  SCIP* scip, /**< SCIP data structure */
11620  SCIP_CONS** conss, /**< constraint set */
11621  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11622  int chkind, /**< index of constraint to check against all prior indices upto startind */
11623  int* ndelconss /**< pointer to count number of deleted constraints */
11624  )
11625 {
11626  SCIP_CONS* cons0;
11627  SCIP_CONSDATA* consdata0;
11628  int c;
11629 
11630  assert(scip != NULL);
11631  assert(conss != NULL);
11632  assert(firstchange <= chkind);
11633  assert(ndelconss != NULL);
11634 
11635  /* get the constraint to be checked against all prior constraints */
11636  cons0 = conss[chkind];
11637  assert(cons0 != NULL);
11638  assert(SCIPconsIsActive(cons0));
11639  assert(!SCIPconsIsModifiable(cons0));
11640 
11641  consdata0 = SCIPconsGetData(cons0);
11642  assert(consdata0 != NULL);
11643  assert(consdata0->nvars >= 1);
11644  assert(consdata0->merged);
11645 
11646  /* sort the constraint */
11647  sortItems(consdata0);
11648 
11649  /* see #2970 */
11650  if( consdata0->capacity == 0 )
11651  return SCIP_OKAY;
11652 
11653  /* check constraint against all prior constraints */
11654  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11655  {
11656  SCIP_CONS* cons1;
11657  SCIP_CONSDATA* consdata1;
11658  SCIP_Bool iscons0incons1contained;
11659  SCIP_Bool iscons1incons0contained;
11660  SCIP_Real quotient;
11661  int v;
11662  int v0;
11663  int v1;
11664 
11665  cons1 = conss[c];
11666  assert(cons1 != NULL);
11667  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11668  continue;
11669 
11670  consdata1 = SCIPconsGetData(cons1);
11671  assert(consdata1 != NULL);
11672 
11673  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11674  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11675  continue;
11676 
11677  assert(consdata1->nvars >= 1);
11678  assert(consdata1->merged);
11679 
11680  /* sort the constraint */
11681  sortItems(consdata1);
11682 
11683  /* see #2970 */
11684  if( consdata1->capacity == 0 )
11685  continue;
11686 
11687  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11688 
11689  if( consdata0->nvars > consdata1->nvars )
11690  {
11691  iscons0incons1contained = FALSE;
11692  iscons1incons0contained = TRUE;
11693  v = consdata1->nvars - 1;
11694  }
11695  else if( consdata0->nvars < consdata1->nvars )
11696  {
11697  iscons0incons1contained = TRUE;
11698  iscons1incons0contained = FALSE;
11699  v = consdata0->nvars - 1;
11700  }
11701  else
11702  {
11703  iscons0incons1contained = TRUE;
11704  iscons1incons0contained = TRUE;
11705  v = consdata0->nvars - 1;
11706  }
11707 
11708  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11709 
11710  /* check consdata0 against consdata1:
11711  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11712  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11713  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11714  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11715  */
11716  v0 = consdata0->nvars - 1;
11717  v1 = consdata1->nvars - 1;
11718 
11719  while( v >= 0 )
11720  {
11721  assert(iscons0incons1contained || iscons1incons0contained);
11722 
11723  /* now there are more variables in cons1 left */
11724  if( v1 > v0 )
11725  {
11726  iscons1incons0contained = FALSE;
11727  if( !iscons0incons1contained )
11728  break;
11729  }
11730  /* now there are more variables in cons0 left */
11731  else if( v1 < v0 )
11732  {
11733  iscons0incons1contained = FALSE;
11734  if( !iscons1incons0contained )
11735  break;
11736  }
11737 
11738  assert(v == v0 || v == v1);
11739  assert(v0 >= 0);
11740  assert(v1 >= 0);
11741 
11742  /* both variables are the same */
11743  if( consdata0->vars[v0] == consdata1->vars[v1] )
11744  {
11745  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11746  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11747  {
11748  iscons1incons0contained = FALSE;
11749  if( !iscons0incons1contained )
11750  break;
11751  }
11752  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11753  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11754  {
11755  iscons0incons1contained = FALSE;
11756  if( !iscons1incons0contained )
11757  break;
11758  }
11759  --v0;
11760  --v1;
11761  --v;
11762  }
11763  else
11764  {
11765  /* both constraints have a variables which is not part of the other constraint, so stop */
11766  if( iscons0incons1contained && iscons1incons0contained )
11767  {
11768  iscons0incons1contained = FALSE;
11769  iscons1incons0contained = FALSE;
11770  break;
11771  }
11772  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11773  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11774  /* continue to the next variable */
11775  if( iscons0incons1contained )
11776  --v1;
11777  else
11778  --v0;
11779  }
11780  }
11781  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11782  * other
11783  */
11784  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11785 
11786  if( iscons1incons0contained )
11787  {
11788  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11789  SCIPdebugPrintCons(scip, cons1, NULL);
11790 
11791  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11792  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11793 
11794  SCIP_CALL( SCIPdelCons(scip, cons1) );
11795  ++(*ndelconss);
11796  }
11797  else if( iscons0incons1contained )
11798  {
11799  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11800  SCIPdebugPrintCons(scip, cons0, NULL);
11801 
11802  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11803  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11804 
11805  SCIP_CALL( SCIPdelCons(scip, cons0) );
11806  ++(*ndelconss);
11807  break;
11808  }
11809  }
11810 
11811  return SCIP_OKAY;
11812 }
11813 
11814 /** helper function to enforce constraints */
11815 static
11817  SCIP* scip, /**< SCIP data structure */
11818  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11819  SCIP_CONS** conss, /**< constraints to process */
11820  int nconss, /**< number of constraints */
11821  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11822  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11823  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11824  )
11825 {
11826  SCIP_CONSHDLRDATA* conshdlrdata;
11827  SCIP_Bool violated;
11828  SCIP_Bool cutoff = FALSE;
11829  int maxncuts;
11830  int ncuts = 0;
11831  int i;
11832 
11833  *result = SCIP_FEASIBLE;
11834 
11835  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11836  sol == NULL ? "LP" : "relaxation");
11837 
11838  /* get maximal number of cuts per round */
11839  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11840  assert(conshdlrdata != NULL);
11841  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11842 
11843  /* search for violated useful knapsack constraints */
11844  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11845  {
11846  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11847  if( violated )
11848  {
11849  /* add knapsack constraint as LP row to the relaxation */
11850  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11851  ncuts++;
11852  }
11853  }
11854 
11855  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11856  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11857  {
11858  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11859  if( violated )
11860  {
11861  /* add knapsack constraint as LP row to the relaxation */
11862  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11863  ncuts++;
11864  }
11865  }
11866 
11867  /* adjust the result code */
11868  if ( cutoff )
11869  *result = SCIP_CUTOFF;
11870  else if ( ncuts > 0 )
11871  *result = SCIP_SEPARATED;
11872 
11873  return SCIP_OKAY;
11874 }
11875 
11876 /*
11877  * Linear constraint upgrading
11878  */
11879 
11880 /** creates and captures a knapsack constraint out of a linear inequality */
11881 static
11883  SCIP* scip, /**< SCIP data structure */
11884  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11885  const char* name, /**< name of constraint */
11886  int nvars, /**< number of variables in the constraint */
11887  SCIP_VAR** vars, /**< array with variables of constraint entries */
11888  SCIP_Real* vals, /**< array with inequality coefficients */
11889  SCIP_Real lhs, /**< left hand side of inequality */
11890  SCIP_Real rhs, /**< right hand side of inequality */
11891  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11892  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11893  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11894  * Usually set to TRUE. */
11895  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11896  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11897  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11898  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11899  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11900  * Usually set to TRUE. */
11901  SCIP_Bool local, /**< is constraint only valid locally?
11902  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11903  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11904  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11905  * adds coefficients to this constraint. */
11906  SCIP_Bool dynamic, /**< is constraint subject to aging?
11907  * Usually set to FALSE. Set to TRUE for own cuts which
11908  * are separated as constraints. */
11909  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11910  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11911  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11912  * if it may be moved to a more global node?
11913  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11914  )
11915 {
11916  SCIP_VAR** transvars;
11917  SCIP_Longint* weights;
11918  SCIP_Longint capacity;
11919  SCIP_Longint weight;
11920  int mult;
11921  int v;
11922 
11923  assert(nvars == 0 || vars != NULL);
11924  assert(nvars == 0 || vals != NULL);
11925  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11926 
11927  /* get temporary memory */
11928  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11929  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11930 
11931  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11932  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11933  */
11934  if( SCIPisInfinity(scip, rhs) )
11935  {
11936  mult = -1;
11937  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11938  }
11939  else
11940  {
11941  mult = +1;
11942  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11943  }
11944 
11945  /* negate positive or negative variables */
11946  for( v = 0; v < nvars; ++v )
11947  {
11948  assert(SCIPisFeasIntegral(scip, vals[v]));
11949  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11950  if( weight > 0 )
11951  {
11952  transvars[v] = vars[v];
11953  weights[v] = weight;
11954  }
11955  else
11956  {
11957  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11958  weights[v] = -weight; /*lint !e2704*/
11959  capacity -= weight;
11960  }
11961  assert(transvars[v] != NULL);
11962  }
11963 
11964  /* create the constraint */
11965  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11966  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11967 
11968  /* free temporary memory */
11969  SCIPfreeBufferArray(scip, &weights);
11970  SCIPfreeBufferArray(scip, &transvars);
11971 
11972  return SCIP_OKAY;
11973 }
11974 
11975 /** tries to upgrade a linear constraint into a knapsack constraint */
11976 static
11977 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11978 { /*lint --e{715}*/
11979  SCIP_Bool upgrade;
11980 
11981  assert(upgdcons != NULL);
11982 
11983  /* check, if linear constraint can be upgraded to a knapsack constraint
11984  * - all variables must be binary
11985  * - all coefficients must be integral
11986  * - exactly one of the sides must be infinite
11987  * note that this includes the case of negative capacity, which has been
11988  * observed to occur, e.g., when upgrading a conflict constraint
11989  */
11990  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11991  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11992  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11993 
11994  if( upgrade )
11995  {
11996  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11997 
11998  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11999  assert(!SCIPconsIsModifiable(cons));
12000  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12005  }
12006 
12007  return SCIP_OKAY;
12008 }
12009 
12010 
12011 /*
12012  * Callback methods of constraint handler
12013  */
12014 
12015 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12016 /**! [SnippetConsCopyKnapsack] */
12017 static
12018 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12019 { /*lint --e{715}*/
12020  assert(scip != NULL);
12021  assert(conshdlr != NULL);
12022  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12023 
12024  /* call inclusion method of constraint handler */
12027  *valid = TRUE;
12028 
12029  return SCIP_OKAY;
12030 }
12031 /**! [SnippetConsCopyKnapsack] */
12032 
12033 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12034 /**! [SnippetConsFreeKnapsack] */
12035 static
12036 SCIP_DECL_CONSFREE(consFreeKnapsack)
12037 { /*lint --e{715}*/
12038  SCIP_CONSHDLRDATA* conshdlrdata;
12039 
12040  /* free constraint handler data */
12041  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12042  assert(conshdlrdata != NULL);
12043 
12044  SCIPfreeBlockMemory(scip, &conshdlrdata);
12045 
12046  SCIPconshdlrSetData(conshdlr, NULL);
12047 
12048  return SCIP_OKAY;
12049 }
12050 /**! [SnippetConsFreeKnapsack] */
12051 
12052 
12053 /** initialization method of constraint handler (called after problem was transformed) */
12054 static
12055 SCIP_DECL_CONSINIT(consInitKnapsack)
12056 { /*lint --e{715}*/
12057  SCIP_CONSHDLRDATA* conshdlrdata;
12058  int nvars;
12059 
12060  assert( scip != NULL );
12061  assert( conshdlr != NULL );
12062 
12063  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12064  assert(conshdlrdata != NULL);
12065 
12066  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12067  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12068 
12069  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12070  conshdlrdata->reals1size = nvars;
12071 
12072  return SCIP_OKAY;
12073 }
12074 
12075 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12076 static
12077 SCIP_DECL_CONSEXIT(consExitKnapsack)
12078 { /*lint --e{715}*/
12079  SCIP_CONSHDLRDATA* conshdlrdata;
12080 
12081  assert( scip != NULL );
12082  assert( conshdlr != NULL );
12083 
12084  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12085  assert(conshdlrdata != NULL);
12086 
12087  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12088  conshdlrdata->reals1size = 0;
12089 
12090  return SCIP_OKAY;
12091 }
12092 
12093 
12094 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12095 static
12096 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12097 { /*lint --e{715}*/
12098  SCIP_CONSHDLRDATA* conshdlrdata;
12099  int nvars;
12100 
12101  assert(scip != NULL);
12102  assert(conshdlr != NULL);
12103  assert(nconss == 0 || conss != NULL);
12105  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12106  assert(conshdlrdata != NULL);
12107 
12108  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12109  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12110 
12111  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12112  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12113  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12114  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12115  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12116  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12117  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12118  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12119 
12120  conshdlrdata->ints1size = nvars;
12121  conshdlrdata->ints2size = nvars;
12122  conshdlrdata->longints1size = nvars;
12123  conshdlrdata->longints2size = nvars;
12124  conshdlrdata->bools1size = nvars;
12125  conshdlrdata->bools2size = nvars;
12126  conshdlrdata->bools3size = nvars;
12127  conshdlrdata->bools4size = nvars;
12128 
12129 #ifdef WITH_CARDINALITY_UPGRADE
12130  conshdlrdata->upgradedcard = FALSE;
12131 #endif
12132 
12133  return SCIP_OKAY;
12134 }
12135 
12136 
12137 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12138 static
12139 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12140 { /*lint --e{715}*/
12141  SCIP_CONSHDLRDATA* conshdlrdata;
12142  int c;
12143 
12144  assert(scip != NULL);
12145  assert(conshdlr != NULL);
12146 
12147  for( c = 0; c < nconss; ++c )
12148  {
12149  if( !SCIPconsIsDeleted(conss[c]) )
12150  {
12151  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12152  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12153  }
12154  }
12155 
12156  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12157  assert(conshdlrdata != NULL);
12158 
12159  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12160  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12161  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12162  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12163  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12164  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12165  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12166  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12167 
12168  conshdlrdata->ints1size = 0;
12169  conshdlrdata->ints2size = 0;
12170  conshdlrdata->longints1size = 0;
12171  conshdlrdata->longints2size = 0;
12172  conshdlrdata->bools1size = 0;
12173  conshdlrdata->bools2size = 0;
12174  conshdlrdata->bools3size = 0;
12175  conshdlrdata->bools4size = 0;
12176 
12177  return SCIP_OKAY;
12178 }
12179 
12180 /** solving process initialization method of constraint handler */
12181 static
12182 SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12183 { /*lint --e{715}*/
12184 
12185  /* add nlrow representation to NLP, if NLP had been constructed */
12186  if( SCIPisNLPConstructed(scip) )
12187  {
12188  int c;
12189  for( c = 0; c < nconss; ++c )
12190  {
12191  SCIP_CALL( addNlrow(scip, conss[c]) );
12192  }
12193  }
12194 
12195  return SCIP_OKAY;
12196 }
12197 
12198 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12199 static
12200 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12201 { /*lint --e{715}*/
12202  SCIP_CONSDATA* consdata;
12203  int c;
12204 
12205  assert( scip != NULL );
12206 
12207  /* release the rows and nlrows of all constraints */
12208  for( c = 0; c < nconss; ++c )
12209  {
12210  consdata = SCIPconsGetData(conss[c]);
12211  assert(consdata != NULL);
12212 
12213  if( consdata->row != NULL )
12214  {
12215  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12216  }
12217 
12218  if( consdata->nlrow != NULL )
12219  {
12220  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12221  }
12222  }
12223 
12224  return SCIP_OKAY;
12225 }
12226 
12227 /** frees specific constraint data */
12228 static
12229 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12230 { /*lint --e{715}*/
12231  SCIP_CONSHDLRDATA* conshdlrdata;
12232 
12233  assert(conshdlr != NULL);
12234  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12235 
12236  /* get event handler */
12237  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12238  assert(conshdlrdata != NULL);
12239  assert(conshdlrdata->eventhdlr != NULL);
12240 
12241  /* free knapsack constraint */
12242  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12243 
12244  return SCIP_OKAY;
12245 }
12246 
12247 /** transforms constraint data into data belonging to the transformed problem */
12248 /**! [SnippetConsTransKnapsack]*/
12249 static
12250 SCIP_DECL_CONSTRANS(consTransKnapsack)
12251 { /*lint --e{715}*/
12252  SCIP_CONSHDLRDATA* conshdlrdata;
12253  SCIP_CONSDATA* sourcedata;
12254  SCIP_CONSDATA* targetdata;
12255 
12256  assert(conshdlr != NULL);
12257  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12259  assert(sourcecons != NULL);
12260  assert(targetcons != NULL);
12261 
12262  sourcedata = SCIPconsGetData(sourcecons);
12263  assert(sourcedata != NULL);
12264  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12265 
12266  /* get event handler */
12267  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12268  assert(conshdlrdata != NULL);
12269  assert(conshdlrdata->eventhdlr != NULL);
12270 
12271  /* create target constraint data */
12272  SCIP_CALL( consdataCreate(scip, &targetdata,
12273  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12274 
12275  /* create target constraint */
12276  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12277  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12278  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12279  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12280  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12281 
12282  /* catch events for variables */
12283  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12284 
12285  return SCIP_OKAY;
12286 }
12287 /**! [SnippetConsTransKnapsack]*/
12288 
12289 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12290 static
12291 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12292 { /*lint --e{715}*/
12293  int i;
12294 
12295  *infeasible = FALSE;
12296 
12297  for( i = 0; i < nconss && !(*infeasible); i++ )
12298  {
12299  assert(SCIPconsIsInitial(conss[i]));
12300  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12301  }
12302 
12303  return SCIP_OKAY;
12304 }
12305 
12306 /** separation method of constraint handler for LP solutions */
12307 static
12308 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12309 { /*lint --e{715}*/
12310  SCIP_CONSHDLRDATA* conshdlrdata;
12311  SCIP_Bool sepacardinality;
12312  SCIP_Bool cutoff;
12313 
12314  SCIP_Real loclowerbound;
12315  SCIP_Real glblowerbound;
12316  SCIP_Real cutoffbound;
12317  SCIP_Real maxbound;
12318 
12319  int depth;
12320  int nrounds;
12321  int sepafreq;
12322  int sepacardfreq;
12323  int ncuts;
12324  int maxsepacuts;
12325  int i;
12326 
12327  *result = SCIP_DIDNOTRUN;
12328 
12329  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12330  assert(conshdlrdata != NULL);
12331 
12332  depth = SCIPgetDepth(scip);
12333  nrounds = SCIPgetNSepaRounds(scip);
12334 
12335  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12336  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12337 
12338  /* only call the separator a given number of times at each node */
12339  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12340  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12341  return SCIP_OKAY;
12342 
12343  /* check, if we should additionally separate knapsack cuts */
12344  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12345  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12346  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12347  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12348 
12349  /* check dual bound to see if we want to produce knapsack cuts at this node */
12350  loclowerbound = SCIPgetLocalLowerbound(scip);
12351  glblowerbound = SCIPgetLowerbound(scip);
12352  cutoffbound = SCIPgetCutoffbound(scip);
12353  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12354  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12355  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12356 
12357  /* get the maximal number of cuts allowed in a separation round */
12358  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12359 
12360  *result = SCIP_DIDNOTFIND;
12361  ncuts = 0;
12362  cutoff = FALSE;
12363 
12364  /* separate useful constraints */
12365  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12366  {
12367  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12368  }
12369 
12370  /* adjust return value */
12371  if ( cutoff )
12372  *result = SCIP_CUTOFF;
12373  else if ( ncuts > 0 )
12374  *result = SCIP_SEPARATED;
12375 
12376  return SCIP_OKAY;
12377 }
12378 
12379 
12380 /** separation method of constraint handler for arbitrary primal solutions */
12381 static
12382 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12383 { /*lint --e{715}*/
12384  SCIP_CONSHDLRDATA* conshdlrdata;
12385  SCIP_Bool sepacardinality;
12386  SCIP_Bool cutoff;
12387 
12388  int depth;
12389  int nrounds;
12390  int sepafreq;
12391  int sepacardfreq;
12392  int ncuts;
12393  int maxsepacuts;
12394  int i;
12395 
12396  *result = SCIP_DIDNOTRUN;
12397 
12398  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12399  assert(conshdlrdata != NULL);
12400 
12401  depth = SCIPgetDepth(scip);
12402  nrounds = SCIPgetNSepaRounds(scip);
12403 
12404  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12405  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12406 
12407  /* only call the separator a given number of times at each node */
12408  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12409  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12410  return SCIP_OKAY;
12411 
12412  /* check, if we should additionally separate knapsack cuts */
12413  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12414  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12415  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12416  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12417 
12418  /* get the maximal number of cuts allowed in a separation round */
12419  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12420 
12421  *result = SCIP_DIDNOTFIND;
12422  ncuts = 0;
12423  cutoff = FALSE;
12424 
12425  /* separate useful constraints */
12426  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12427  {
12428  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12429  }
12430 
12431  /* adjust return value */
12432  if ( cutoff )
12433  *result = SCIP_CUTOFF;
12434  else if( ncuts > 0 )
12435  *result = SCIP_SEPARATED;
12436 
12437  return SCIP_OKAY;
12438 }
12439 
12440 /** constraint enforcing method of constraint handler for LP solutions */
12441 static
12442 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12443 { /*lint --e{715}*/
12444  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12445 
12446  return SCIP_OKAY;
12447 }
12448 
12449 /** constraint enforcing method of constraint handler for relaxation solutions */
12450 static
12451 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12452 { /*lint --e{715}*/
12453  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12454 
12455  return SCIP_OKAY;
12456 }
12457 
12458 /** constraint enforcing method of constraint handler for pseudo solutions */
12459 static
12460 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12461 { /*lint --e{715}*/
12462  SCIP_Bool violated;
12463  int i;
12464 
12465  for( i = 0; i < nconss; i++ )
12466  {
12467  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12468  if( violated )
12469  {
12470  *result = SCIP_INFEASIBLE;
12471  return SCIP_OKAY;
12472  }
12473  }
12474  *result = SCIP_FEASIBLE;
12475 
12476  return SCIP_OKAY;
12477 }
12478 
12479 /** feasibility check method of constraint handler for integral solutions */
12480 static
12481 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12482 { /*lint --e{715}*/
12483  SCIP_Bool violated;
12484  int i;
12485 
12486  *result = SCIP_FEASIBLE;
12487 
12488  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12489  {
12490  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12491  if( violated )
12492  *result = SCIP_INFEASIBLE;
12493  }
12494 
12495  return SCIP_OKAY;
12496 }
12497 
12498 /** domain propagation method of constraint handler */
12499 static
12500 SCIP_DECL_CONSPROP(consPropKnapsack)
12501 { /*lint --e{715}*/
12502  SCIP_CONSHDLRDATA* conshdlrdata;
12503  SCIP_Bool cutoff;
12504  SCIP_Bool redundant;
12505  SCIP_Bool inpresolve;
12506  int nfixedvars;
12507  int i;
12509  cutoff = FALSE;
12510  nfixedvars = 0;
12511 
12512  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12513  assert(conshdlrdata != NULL);
12514 
12515  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12516  assert(!inpresolve || SCIPinProbing(scip));
12517 
12518  /* process useful constraints */
12519  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12520  {
12521  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12522  * otherwise the multi-aggregation should be resolved
12523  */
12524  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12525  continue;
12526 #ifndef NDEBUG
12527  else
12528  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12529 #endif
12530 
12531  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12532 
12533  /* unmark the constraint to be propagated */
12534  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12535  }
12536 
12537  /* adjust result code */
12538  if( cutoff )
12539  *result = SCIP_CUTOFF;
12540  else if( nfixedvars > 0 )
12541  *result = SCIP_REDUCEDDOM;
12542  else
12543  *result = SCIP_DIDNOTFIND;
12544 
12545  return SCIP_OKAY; /*lint !e438*/
12546 }
12547 
12548 /** presolving method of constraint handler */
12549 static
12550 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12551 { /*lint --e{574,715}*/
12552  SCIP_CONSHDLRDATA* conshdlrdata;
12553  SCIP_CONSDATA* consdata;
12554  SCIP_CONS* cons;
12555  SCIP_Bool cutoff;
12556  SCIP_Bool redundant;
12557  SCIP_Bool success;
12558  int oldnfixedvars;
12559  int oldnchgbds;
12560  int oldndelconss;
12561  int oldnaddconss;
12562  int oldnchgcoefs;
12563  int oldnchgsides;
12564  int firstchange;
12565  int c;
12566  SCIP_Bool newchanges;
12567 
12568  /* remember old preprocessing counters */
12569  cutoff = FALSE;
12570  oldnfixedvars = *nfixedvars;
12571  oldnchgbds = *nchgbds;
12572  oldndelconss = *ndelconss;
12573  oldnaddconss = *naddconss;
12574  oldnchgcoefs = *nchgcoefs;
12575  oldnchgsides = *nchgsides;
12576  firstchange = INT_MAX;
12577 
12578  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12579 
12580  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12581  assert(conshdlrdata != NULL);
12582 
12583  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12584  {
12585  int thisnfixedvars;
12586  int thisnchgbds;
12587 
12588  cons = conss[c];
12589  consdata = SCIPconsGetData(cons);
12590  assert(consdata != NULL);
12591 
12592  /* update data structures */
12593  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12594  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12595  {
12596  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12597  if( cutoff )
12598  break;
12599  }
12600 
12601  /* force presolving the constraint in the initial round */
12602  if( nrounds == 0 )
12603  consdata->presolvedtiming = 0;
12604  else if( consdata->presolvedtiming >= presoltiming )
12605  continue;
12606 
12607  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12608  SCIPdebugPrintCons(scip, cons, NULL);
12609  consdata->presolvedtiming = presoltiming;
12610 
12611  thisnfixedvars = *nfixedvars;
12612  thisnchgbds = *nchgbds;
12613 
12614  /* merge constraint, so propagation works better */
12615  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12616  if( cutoff )
12617  break;
12618 
12619  /* add cliques in the knapsack to the clique table */
12620  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12621  {
12622  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12623  if( cutoff )
12624  break;
12625  }
12626 
12627  /* propagate constraint */
12628  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12629  {
12630  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12631 
12632  if( cutoff )
12633  break;
12634  if( redundant )
12635  {
12636  (*ndelconss)++;
12637  continue;
12638  }
12639  }
12640 
12641  /* remove again all fixed variables, if further fixings were found */
12642  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12643  {
12644  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12645  if( cutoff )
12646  break;
12647 
12648  thisnfixedvars = *nfixedvars;
12649  }
12650 
12651  if( !SCIPconsIsModifiable(cons) )
12652  {
12653  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12654  if( consdata->weightsum <= consdata->capacity )
12655  {
12656  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12657  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12658  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12659  continue;
12660  }
12661 
12662  /* divide weights by their greatest common divisor */
12663  normalizeWeights(cons, nchgcoefs, nchgsides);
12664 
12665  /* try to simplify inequalities */
12666  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12667  {
12668  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12669  if( cutoff )
12670  break;
12671 
12672  if( SCIPconsIsDeleted(cons) )
12673  continue;
12674 
12675  /* remove again all fixed variables, if further fixings were found */
12676  if( *nfixedvars > thisnfixedvars )
12677  {
12678  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12679  if( cutoff )
12680  break;
12681  }
12682  }
12683 
12684  /* tighten capacity and weights */
12685  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12686  if( cutoff )
12687  break;
12688 
12689  if( SCIPconsIsActive(cons) )
12690  {
12691  if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12692  {
12693  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12694  * dual reduction
12695  */
12696  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12697  if( redundant )
12698  continue;
12699  }
12700 
12701  /* check if knapsack constraint is parallel to objective function */
12702  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12703  }
12704  }
12705  /* remember the first changed constraint to begin the next aggregation round with */
12706  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12707  firstchange = c;
12708  }
12709 
12710  /* preprocess pairs of knapsack constraints */
12711  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12712  {
12713  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12714  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12715  }
12716 
12717  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12718  success = TRUE;
12719  else
12720  success = FALSE;
12721 
12722  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12723  {
12724  SCIP_Longint npaircomparisons;
12725 
12726  npaircomparisons = 0;
12727  oldndelconss = *ndelconss;
12728  oldnchgsides = *nchgsides;
12729  oldnchgcoefs = *nchgcoefs;
12730 
12731  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12732  {
12733  cons = conss[c];
12734  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12735  continue;
12736 
12737  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12738 
12739  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12740 
12741  if( npaircomparisons > NMINCOMPARISONS )
12742  {
12743  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12744  success = TRUE;
12745  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12746  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12747  break;
12748  oldndelconss = *ndelconss;
12749  oldnchgsides = *nchgsides;
12750  oldnchgcoefs = *nchgcoefs;
12751  npaircomparisons = 0;
12752  }
12753  }
12754  }
12755 #ifdef WITH_CARDINALITY_UPGRADE
12756  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12757  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12758  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12759  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12760  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12761  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12762  * as well, we better keep this code disabled. */
12763  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12764  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12765  {
12766  SCIP_HASHMAP* varhash;
12767  SCIP_VAR** cardvars;
12768  SCIP_Real* cardweights;
12769  int noldupgdconss;
12770  int nscipvars;
12771  int makeupgrade;
12772 
12773  noldupgdconss = *nupgdconss;
12774  nscipvars = SCIPgetNVars(scip);
12775  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12776  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12777 
12778  /* set up hash map */
12779  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12780 
12781  /* We loop through all cardinality constraints twice:
12782  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12783  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12784  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12785  * - Second, upgrade knapsack constraints to cardinality constraints. */
12786  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12787  {
12788  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12789  {
12790  SCIP_CONS* cardcons;
12791  SCIP_VAR** vars;
12792  SCIP_Longint* weights;
12793  int nvars;
12794  int v;
12795 
12796  cons = conss[c];
12797  assert( cons != NULL );
12798  consdata = SCIPconsGetData(cons);
12799  assert( consdata != NULL );
12800 
12801  nvars = consdata->nvars;
12802  vars = consdata->vars;
12803  weights = consdata->weights;
12804 
12805  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12806  * - all variables must be binary (always true)
12807  * - all coefficients must be 1.0
12808  * - the right hand side must be smaller than nvars
12809  */
12810  if ( consdata->capacity >= nvars )
12811  continue;
12812 
12813  /* the weights are sorted: check first and last weight */
12814  assert( consdata->sorted );
12815  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12816  continue;
12817 
12818  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12819  for (v = 0; v < nvars; ++v)
12820  {
12821  SCIP_BOUNDTYPE* impltypes;
12822  SCIP_Real* implbounds;
12823  SCIP_VAR** implvars;
12824  SCIP_VAR* var;
12825  int nimpls;
12826  int j;
12827 
12828  var = consdata->vars[v];
12829  assert( var != NULL );
12830  assert( SCIPvarIsBinary(var) );
12831 
12832  /* ignore non-active variables */
12833  if ( ! SCIPvarIsActive(var) )
12834  break;
12835 
12836  /* be sure that implication variable has zero objective */
12837  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12838  break;
12839 
12840  nimpls = SCIPvarGetNImpls(var, FALSE);
12841  implvars = SCIPvarGetImplVars(var, FALSE);
12842  implbounds = SCIPvarGetImplBounds(var, FALSE);
12843  impltypes = SCIPvarGetImplTypes(var, FALSE);
12844 
12845  for (j = 0; j < nimpls; ++j)
12846  {
12847  /* be sure that continuous variable is fixed to 0 */
12848  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12849  continue;
12850 
12851  /* cannot currently deal with nonzero fixings */
12852  if ( ! SCIPisZero(scip, implbounds[j]) )
12853  continue;
12854 
12855  /* number of down locks should be one */
12856  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12857  continue;
12858 
12859  cardvars[v] = implvars[j];
12860  cardweights[v] = (SCIP_Real) v;
12861 
12862  break;
12863  }
12864 
12865  /* found no variable upper bound candidate -> exit */
12866  if ( j >= nimpls )
12867  break;
12868  }
12869 
12870  /* did not find fitting variable upper bound for some variable -> exit */
12871  if ( v < nvars )
12872  break;
12873 
12874  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12875  * in which the binary variable is involved in */
12876  if ( makeupgrade == 0 )
12877  {
12878  for (v = 0; v < nvars; ++v)
12879  {
12880  if ( SCIPhashmapExists(varhash, vars[v]) )
12881  {
12882  int image;
12883 
12884  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12885  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12886  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12887  }
12888  else
12889  {
12890  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12891  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12892  assert( SCIPhashmapExists(varhash, vars[v]) );
12893  }
12894  }
12895  }
12896  else
12897  {
12898  SCIP_CONS* origcons;
12899 
12900  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12901  * knapsack constraint coincides with the number of variable up locks */
12902  for (v = 0; v < nvars; ++v)
12903  {
12904  assert( SCIPhashmapExists(varhash, vars[v]) );
12905  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12906  break;
12907  }
12908  if ( v < nvars )
12909  break;
12910 
12911  /* store that we have upgraded */
12912  conshdlrdata->upgradedcard = TRUE;
12913 
12914  /* at this point we found suitable variable upper bounds */
12915  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12916 
12917  /* create cardinality constraint */
12918  assert( ! SCIPconsIsModifiable(cons) );
12919  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12923 #ifdef SCIP_DEBUG
12924  SCIPprintCons(scip, cons, NULL);
12925  SCIPinfoMessage(scip, NULL, "\n");
12926  SCIPprintCons(scip, cardcons, NULL);
12927  SCIPinfoMessage(scip, NULL, "\n");
12928 #endif
12929  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12930  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12931  ++(*nupgdconss);
12932 
12933  /* delete oknapsack constraint */
12934  SCIP_CALL( SCIPdelCons(scip, cons) );
12935  ++(*ndelconss);
12936 
12937  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12938  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12939  * although the cardinality constraint is satisfied. */
12940  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12941  assert( origcons != NULL );
12942  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12943 
12944  for (v = 0; v < nvars; ++v)
12945  {
12946  int image;
12947 
12948  assert ( SCIPhashmapExists(varhash, vars[v]) );
12949  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12950  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12951  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12952  }
12953  }
12954  }
12955  }
12956  SCIPhashmapFree(&varhash);
12957  SCIPfreeBufferArray(scip, &cardweights);
12958  SCIPfreeBufferArray(scip, &cardvars);
12959 
12960  if ( *nupgdconss > noldupgdconss )
12961  success = TRUE;
12962  }
12963 #endif
12964 
12965  if( cutoff )
12966  *result = SCIP_CUTOFF;
12967  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12968  *result = SCIP_SUCCESS;
12969  else
12970  *result = SCIP_DIDNOTFIND;
12971 
12972  return SCIP_OKAY;
12973 }
12974 
12975 /** propagation conflict resolving method of constraint handler */
12976 static
12977 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12978 { /*lint --e{715}*/
12979  SCIP_CONSDATA* consdata;
12980  SCIP_Longint capsum;
12981  int i;
12982 
12983  assert(result != NULL);
12984 
12985  consdata = SCIPconsGetData(cons);
12986  assert(consdata != NULL);
12987 
12988  /* check if we fixed a binary variable to one (due to negated clique) */
12989  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12990  {
12991  for( i = 0; i < consdata->nvars; ++i )
12992  {
12993  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12994  {
12995  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12996  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12997  break;
12998  }
12999  }
13000  assert(i < consdata->nvars);
13001  }
13002  else
13003  {
13004  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13005  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13006  * knapsack constraint, see one above call of SCIPinferBinvarCons
13007  */
13008  if( inferinfo < 0 )
13009  capsum = 0;
13010  else
13011  {
13012  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13013  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13014  */
13015  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13016  capsum = consdata->weights[inferinfo];
13017  else
13018  {
13019  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13020  {}
13021  assert(i < consdata->nvars);
13022  capsum = consdata->weights[i];
13023  }
13024  }
13025 
13026  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13027  * the capacity
13028  */
13029  if( capsum <= consdata->capacity )
13030  {
13031  for( i = 0; i < consdata->nvars; i++ )
13032  {
13033  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13034  {
13035  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13036  capsum += consdata->weights[i];
13037  if( capsum > consdata->capacity )
13038  break;
13039  }
13040  }
13041  }
13042  }
13043 
13044  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13045  * to zero can included negated clique information. A negated clique means, that at most one of the clique
13046  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13047  * used to fix variables to zero.
13048  *
13049  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13050  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13051  * one.
13052  */
13053  *result = SCIP_SUCCESS;
13054 
13055  return SCIP_OKAY;
13056 }
13057 
13058 /** variable rounding lock method of constraint handler */
13059 /**! [SnippetConsLockKnapsack] */
13060 static
13061 SCIP_DECL_CONSLOCK(consLockKnapsack)
13062 { /*lint --e{715}*/
13063  SCIP_CONSDATA* consdata;
13064  int i;
13065 
13066  consdata = SCIPconsGetData(cons);
13067  assert(consdata != NULL);
13068 
13069  for( i = 0; i < consdata->nvars; i++)
13070  {
13071  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13072  }
13073 
13074  return SCIP_OKAY;
13075 }
13076 /**! [SnippetConsLockKnapsack] */
13077 
13078 /** constraint activation notification method of constraint handler */
13079 static
13080 SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13081 { /*lint --e{715}*/
13082 
13083  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisNLPConstructed(scip) )
13084  {
13085  SCIP_CALL( addNlrow(scip, cons) );
13086  }
13087 
13088  return SCIP_OKAY;
13089 }
13090 
13091 /** constraint deactivation notification method of constraint handler */
13092 static
13093 SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13094 { /*lint --e{715}*/
13095  SCIP_CONSDATA* consdata;
13096 
13097  assert(cons != NULL);
13098 
13099  consdata = SCIPconsGetData(cons);
13100  assert(consdata != NULL);
13102  /* remove row from NLP, if still in solving
13103  * if we are in exitsolve, the whole NLP will be freed anyway
13104  */
13105  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13106  {
13107  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13108  }
13109 
13110  return SCIP_OKAY;
13111 }
13112 
13113 /** variable deletion method of constraint handler */
13114 static
13115 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13116 {
13117  assert(scip != NULL);
13118  assert(conshdlr != NULL);
13119  assert(conss != NULL || nconss == 0);
13120 
13121  if( nconss > 0 )
13122  {
13123  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13124  }
13125 
13126  return SCIP_OKAY;
13127 }
13128 
13129 /** constraint display method of constraint handler */
13130 static
13131 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13132 { /*lint --e{715}*/
13133  SCIP_CONSDATA* consdata;
13134  int i;
13135 
13136  assert( scip != NULL );
13137  assert( conshdlr != NULL );
13138  assert( cons != NULL );
13140  consdata = SCIPconsGetData(cons);
13141  assert(consdata != NULL);
13142 
13143  for( i = 0; i < consdata->nvars; ++i )
13144  {
13145  if( i > 0 )
13146  SCIPinfoMessage(scip, file, " ");
13147  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13148  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13149  }
13150  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13151 
13152  return SCIP_OKAY;
13153 }
13154 
13155 /** constraint copying method of constraint handler */
13156 static
13157 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13158 { /*lint --e{715}*/
13159  SCIP_VAR** sourcevars;
13160  SCIP_Longint* weights;
13161  SCIP_Real* coefs;
13162  const char* consname;
13163  int nvars;
13164  int v;
13166  /* get variables and coefficients of the source constraint */
13167  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13168  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13169  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13170 
13171  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13172  for( v = 0; v < nvars; ++v )
13173  coefs[v] = (SCIP_Real) weights[v];
13174 
13175  if( name != NULL )
13176  consname = name;
13177  else
13178  consname = SCIPconsGetName(sourcecons);
13179 
13180  /* copy the logic using the linear constraint copy method */
13181  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13182  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13183  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13184  assert(cons != NULL);
13185 
13186  SCIPfreeBufferArray(scip, &coefs);
13187 
13188  return SCIP_OKAY;
13189 }
13190 
13191 /** constraint parsing method of constraint handler */
13192 static
13193 SCIP_DECL_CONSPARSE(consParseKnapsack)
13194 { /*lint --e{715}*/
13195  SCIP_VAR* var;
13196  SCIP_Longint weight;
13197  SCIP_VAR** vars;
13198  SCIP_Longint* weights;
13199  SCIP_Longint capacity;
13200  char* endptr;
13201  int nread;
13202  int nvars;
13203  int varssize;
13204 
13205  assert(scip != NULL);
13206  assert(success != NULL);
13207  assert(str != NULL);
13208  assert(name != NULL);
13209  assert(cons != NULL);
13210 
13211  *success = TRUE;
13212 
13213  nvars = 0;
13214  varssize = 5;
13215  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13216  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13217 
13218  while( *str != '\0' )
13219  {
13220  /* try to parse coefficient, and stop if not successful (probably reached <=) */
13221  if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13222  break;
13223 
13224  str += nread;
13225 
13226  /* skip whitespace */
13227  while( isspace((int)*str) )
13228  ++str;
13229 
13230  /* parse variable name */
13231  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13232  if( var == NULL )
13233  {
13234  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13235  *success = FALSE;
13236  break;
13237  }
13238 
13239  str = endptr;
13240 
13241  /* store weight and variable */
13242  if( varssize <= nvars )
13243  {
13244  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13245  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13246  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13247  }
13248 
13249  vars[nvars] = var;
13250  weights[nvars] = weight;
13251  ++nvars;
13252 
13253  /* skip whitespace */
13254  while( isspace((int)*str) )
13255  ++str;
13256  }
13257 
13258  if( *success )
13259  {
13260  if( strncmp(str, "<= ", 3) != 0 )
13261  {
13262  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13263  *success = FALSE;
13264  }
13265  else
13266  {
13267  str += 3;
13268  }
13269  }
13270 
13271  if( *success )
13272  {
13273  /* coverity[secure_coding] */
13274  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13275  {
13276  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13277  *success = FALSE;
13278  }
13279  else
13280  {
13281  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13282  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13283  }
13284  }
13285 
13286  SCIPfreeBufferArray(scip, &vars);
13287  SCIPfreeBufferArray(scip, &weights);
13288 
13289  return SCIP_OKAY;
13290 }
13291 
13292 /** constraint method of constraint handler which returns the variables (if possible) */
13293 static
13294 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13295 { /*lint --e{715}*/
13296  SCIP_CONSDATA* consdata;
13297 
13298  consdata = SCIPconsGetData(cons);
13299  assert(consdata != NULL);
13300 
13301  if( varssize < consdata->nvars )
13302  (*success) = FALSE;
13303  else
13304  {
13305  assert(vars != NULL);
13306 
13307  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13308  (*success) = TRUE;
13309  }
13310 
13311  return SCIP_OKAY;
13312 }
13313 
13314 /** constraint method of constraint handler which returns the number of variables (if possible) */
13315 static
13316 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13317 { /*lint --e{715}*/
13318  SCIP_CONSDATA* consdata;
13319 
13320  consdata = SCIPconsGetData(cons);
13321  assert(consdata != NULL);
13322 
13323  (*nvars) = consdata->nvars;
13324  (*success) = TRUE;
13325 
13326  return SCIP_OKAY;
13327 }
13328 
13329 /*
13330  * Event handler
13331  */
13332 
13333 /** execution method of bound change event handler */
13334 static
13335 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13336 { /*lint --e{715}*/
13337  SCIP_CONSDATA* consdata;
13338 
13339  assert(eventdata != NULL);
13340  assert(eventdata->cons != NULL);
13341 
13342  consdata = SCIPconsGetData(eventdata->cons);
13343  assert(consdata != NULL);
13344 
13345  switch( SCIPeventGetType(event) )
13346  {
13348  consdata->onesweightsum += eventdata->weight;
13349  consdata->presolvedtiming = 0;
13350  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13351  break;
13353  consdata->onesweightsum -= eventdata->weight;
13354  break;
13356  consdata->presolvedtiming = 0;
13357  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13358  break;
13359  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13360  if( !consdata->existmultaggr )
13361  {
13362  SCIP_VAR* var;
13363  var = SCIPeventGetVar(event);
13364  assert(var != NULL);
13365 
13366  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13368  {
13369  consdata->existmultaggr = TRUE;
13370  consdata->merged = FALSE;
13371  }
13372  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13374  consdata->merged = FALSE;
13375  }
13376  /*lint -fallthrough*/
13377  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13378  consdata->presolvedtiming = 0;
13379  break;
13381  consdata->varsdeleted = TRUE;
13382  break;
13383  default:
13384  SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13385  return SCIP_INVALIDDATA;
13386  }
13387 
13388  return SCIP_OKAY;
13389 }
13390 
13391 
13392 /*
13393  * constraint specific interface methods
13394  */
13395 
13396 /** creates the handler for knapsack constraints and includes it in SCIP */
13398  SCIP* scip /**< SCIP data structure */
13399  )
13400 {
13401  SCIP_EVENTHDLRDATA* eventhdlrdata;
13402  SCIP_CONSHDLRDATA* conshdlrdata;
13403  SCIP_CONSHDLR* conshdlr;
13404 
13405  /* create knapsack constraint handler data */
13406  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13407 
13408  /* include event handler for bound change events */
13409  eventhdlrdata = NULL;
13410  conshdlrdata->eventhdlr = NULL;
13411  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13412  eventExecKnapsack, eventhdlrdata) );
13413 
13414  /* get event handler for bound change events */
13415  if( conshdlrdata->eventhdlr == NULL )
13416  {
13417  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13418  return SCIP_PLUGINNOTFOUND;
13419  }
13420 
13421  /* include constraint handler */
13424  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13425  conshdlrdata) );
13426 
13427  assert(conshdlr != NULL);
13428 
13429  /* set non-fundamental callbacks via specific setter functions */
13430  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13431  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13432  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13433  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13434  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13435  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13436  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13437  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13438  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13439  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13440  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13441  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13442  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13443  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13444  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13445  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13446  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13447  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13448  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13450  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13451  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13453  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13454  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13455 
13456  if( SCIPfindConshdlr(scip,"linear") != NULL )
13457  {
13458  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13460  }
13461 
13462  /* add knapsack constraint handler parameters */
13463  SCIP_CALL( SCIPaddIntParam(scip,
13464  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13465  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13466  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13468  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13469  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13470  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13472  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13473  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13474  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13475  SCIP_CALL( SCIPaddIntParam(scip,
13476  "constraints/" CONSHDLR_NAME "/maxrounds",
13477  "maximal number of separation rounds per node (-1: unlimited)",
13478  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13479  SCIP_CALL( SCIPaddIntParam(scip,
13480  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13481  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13482  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13483  SCIP_CALL( SCIPaddIntParam(scip,
13484  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13485  "maximal number of cuts separated per separation round",
13486  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13487  SCIP_CALL( SCIPaddIntParam(scip,
13488  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13489  "maximal number of cuts separated per separation round in the root node",
13490  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13492  "constraints/" CONSHDLR_NAME "/disaggregation",
13493  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13494  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13496  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13497  "should presolving try to simplify knapsacks",
13498  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13500  "constraints/" CONSHDLR_NAME "/negatedclique",
13501  "should negated clique information be used in solving process",
13502  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13504  "constraints/" CONSHDLR_NAME "/presolpairwise",
13505  "should pairwise constraint comparison be performed in presolving?",
13506  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13508  "constraints/" CONSHDLR_NAME "/presolusehashing",
13509  "should hash table be used for detecting redundant constraints in advance",
13510  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13512  "constraints/" CONSHDLR_NAME "/dualpresolving",
13513  "should dual presolving steps be performed?",
13514  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13516  "constraints/" CONSHDLR_NAME "/usegubs",
13517  "should GUB information be used for separation?",
13518  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13520  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13521  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13522  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13524  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13525  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13526  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13528  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13529  "should clique partition information be updated when old partition seems outdated?",
13530  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13532  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13533  "factor on the growth of global cliques to decide when to update a previous "
13534  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13535  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13536 #ifdef WITH_CARDINALITY_UPGRADE
13538  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13539  "if TRUE then try to update knapsack constraints to cardinality constraints",
13540  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13541 #endif
13542  return SCIP_OKAY;
13543 }
13544 
13545 /** creates and captures a knapsack constraint
13546  *
13547  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13548  */
13549 /**! [SnippetConsCreationKnapsack] */
13551  SCIP* scip, /**< SCIP data structure */
13552  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13553  const char* name, /**< name of constraint */
13554  int nvars, /**< number of items in the knapsack */
13555  SCIP_VAR** vars, /**< array with item variables */
13556  SCIP_Longint* weights, /**< array with item weights */
13557  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13558  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13559  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13560  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13561  * Usually set to TRUE. */
13562  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13563  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13564  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13565  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13566  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13567  * Usually set to TRUE. */
13568  SCIP_Bool local, /**< is constraint only valid locally?
13569  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13570  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13571  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13572  * adds coefficients to this constraint. */
13573  SCIP_Bool dynamic, /**< is constraint subject to aging?
13574  * Usually set to FALSE. Set to TRUE for own cuts which
13575  * are separated as constraints. */
13576  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13577  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13578  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13579  * if it may be moved to a more global node?
13580  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13581  )
13582 {
13583  SCIP_CONSHDLRDATA* conshdlrdata;
13584  SCIP_CONSHDLR* conshdlr;
13585  SCIP_CONSDATA* consdata;
13586 
13587  /* find the knapsack constraint handler */
13588  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13589  if( conshdlr == NULL )
13590  {
13591  SCIPerrorMessage("knapsack constraint handler not found\n");
13592  return SCIP_PLUGINNOTFOUND;
13593  }
13594 
13595  /* get event handler */
13596  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13597  assert(conshdlrdata != NULL);
13598  assert(conshdlrdata->eventhdlr != NULL);
13599 
13600  /* create constraint data */
13601  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13602 
13603  /* create constraint */
13604  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13605  local, modifiable, dynamic, removable, stickingatnode) );
13606 
13607  /* catch events for variables */
13608  if( SCIPisTransformed(scip) )
13609  {
13610  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13611  }
13612 
13613  return SCIP_OKAY;
13614 }
13615 /**! [SnippetConsCreationKnapsack] */
13616 
13617 /** creates and captures a knapsack constraint
13618  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13619  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13620  *
13621  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13622  *
13623  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13624  */
13626  SCIP* scip, /**< SCIP data structure */
13627  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13628  const char* name, /**< name of constraint */
13629  int nvars, /**< number of items in the knapsack */
13630  SCIP_VAR** vars, /**< array with item variables */
13631  SCIP_Longint* weights, /**< array with item weights */
13632  SCIP_Longint capacity /**< capacity of knapsack */
13633  )
13634 {
13635  assert(scip != NULL);
13636 
13637  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13638  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13639 
13640  return SCIP_OKAY;
13641 }
13642 
13643 /** adds new item to knapsack constraint */
13645  SCIP* scip, /**< SCIP data structure */
13646  SCIP_CONS* cons, /**< constraint data */
13647  SCIP_VAR* var, /**< item variable */
13648  SCIP_Longint weight /**< item weight */
13649  )
13650 {
13651  assert(var != NULL);
13652  assert(scip != NULL);
13653 
13654  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13655  {
13656  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13657  return SCIP_INVALIDDATA;
13658  }
13659 
13660  SCIP_CALL( addCoef(scip, cons, var, weight) );
13661 
13662  return SCIP_OKAY;
13663 }
13664 
13665 /** gets the capacity of the knapsack constraint */
13667  SCIP* scip, /**< SCIP data structure */
13668  SCIP_CONS* cons /**< constraint data */
13669  )
13670 {
13671  SCIP_CONSDATA* consdata;
13672 
13673  assert(scip != NULL);
13675  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13676  {
13677  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13678  SCIPABORT();
13679  return 0; /*lint !e527*/
13680  }
13681 
13682  consdata = SCIPconsGetData(cons);
13683  assert(consdata != NULL);
13684 
13685  return consdata->capacity;
13686 }
13687 
13688 /** changes capacity of the knapsack constraint
13689  *
13690  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13691  */
13693  SCIP* scip, /**< SCIP data structure */
13694  SCIP_CONS* cons, /**< constraint data */
13695  SCIP_Longint capacity /**< new capacity of knapsack */
13696  )
13697 {
13698  SCIP_CONSDATA* consdata;
13699 
13700  assert(scip != NULL);
13701 
13702  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13703  {
13704  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13705  return SCIP_INVALIDDATA;
13706  }
13707 
13708  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13709  {
13710  SCIPerrorMessage("method can only be called during problem creation stage\n");
13711  return SCIP_INVALIDDATA;
13712  }
13713 
13714  consdata = SCIPconsGetData(cons);
13715  assert(consdata != NULL);
13716 
13717  consdata->capacity = capacity;
13718 
13719  return SCIP_OKAY;
13720 }
13721 
13722 /** gets the number of items in the knapsack constraint */
13724  SCIP* scip, /**< SCIP data structure */
13725  SCIP_CONS* cons /**< constraint data */
13726  )
13727 {
13728  SCIP_CONSDATA* consdata;
13729 
13730  assert(scip != NULL);
13732  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13733  {
13734  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13735  SCIPABORT();
13736  return -1; /*lint !e527*/
13737  }
13738 
13739  consdata = SCIPconsGetData(cons);
13740  assert(consdata != NULL);
13741 
13742  return consdata->nvars;
13743 }
13744 
13745 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13747  SCIP* scip, /**< SCIP data structure */
13748  SCIP_CONS* cons /**< constraint data */
13749  )
13750 {
13751  SCIP_CONSDATA* consdata;
13752 
13753  assert(scip != NULL);
13755  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13756  {
13757  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13758  SCIPABORT();
13759  return NULL; /*lint !e527*/
13760  }
13761 
13762  consdata = SCIPconsGetData(cons);
13763  assert(consdata != NULL);
13764 
13765  return consdata->vars;
13766 }
13767 
13768 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13770  SCIP* scip, /**< SCIP data structure */
13771  SCIP_CONS* cons /**< constraint data */
13772  )
13773 {
13774  SCIP_CONSDATA* consdata;
13775 
13776  assert(scip != NULL);
13778  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13779  {
13780  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13781  SCIPABORT();
13782  return NULL; /*lint !e527*/
13783  }
13784 
13785  consdata = SCIPconsGetData(cons);
13786  assert(consdata != NULL);
13787 
13788  return consdata->weights;
13789 }
13790 
13791 /** gets the dual solution of the knapsack constraint in the current LP */
13793  SCIP* scip, /**< SCIP data structure */
13794  SCIP_CONS* cons /**< constraint data */
13795  )
13796 {
13797  SCIP_CONSDATA* consdata;
13798 
13799  assert(scip != NULL);
13801  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13802  {
13803  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13804  SCIPABORT();
13805  return SCIP_INVALID; /*lint !e527*/
13806  }
13807 
13808  consdata = SCIPconsGetData(cons);
13809  assert(consdata != NULL);
13810 
13811  if( consdata->row != NULL )
13812  return SCIProwGetDualsol(consdata->row);
13813  else
13814  return 0.0;
13815 }
13816 
13817 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13819  SCIP* scip, /**< SCIP data structure */
13820  SCIP_CONS* cons /**< constraint data */
13821  )
13822 {
13823  SCIP_CONSDATA* consdata;
13824 
13825  assert(scip != NULL);
13827  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13828  {
13829  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13830  SCIPABORT();
13831  return SCIP_INVALID; /*lint !e527*/
13832  }
13833 
13834  consdata = SCIPconsGetData(cons);
13835  assert(consdata != NULL);
13836 
13837  if( consdata->row != NULL )
13838  return SCIProwGetDualfarkas(consdata->row);
13839  else
13840  return 0.0;
13841 }
13842 
13843 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13844  * the user must not modify the row!
13845  */
13847  SCIP* scip, /**< SCIP data structure */
13848  SCIP_CONS* cons /**< constraint data */
13849  )
13850 {
13851  SCIP_CONSDATA* consdata;
13852 
13853  assert(scip != NULL);
13855  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13856  {
13857  SCIPerrorMessage("constraint is not a knapsack\n");
13858  SCIPABORT();
13859  return NULL; /*lint !e527*/
13860  }
13861 
13862  consdata = SCIPconsGetData(cons);
13863  assert(consdata != NULL);
13864 
13865  return consdata->row;
13866 }
13867 
13868 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
13870  SCIP* scip, /**< SCIP data structure */
13871  SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13872  SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13873  )
13874 {
13875  SCIP_CONSHDLR* conshdlr;
13876  SCIP_CONS** conss;
13877  int nconss;
13878  int i;
13879 
13880  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13881  if( conshdlr == NULL )
13882  return SCIP_OKAY;
13883 
13884  assert(infeasible != NULL);
13885  *infeasible = FALSE;
13886 
13887  nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13888  conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13889 
13890  for( i = 0; i < nconss; ++i )
13891  {
13892  SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13893 
13894  if( *infeasible )
13895  break;
13896  }
13897 
13898  return SCIP_OKAY;
13899 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define KNAPSACKRELAX_MAXSCALE
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
int * gubconssidx
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4214
#define DEFAULT_DETECTCUTOFFBOUND
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1730
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1422
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1699
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:572
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
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:18133
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:11483
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3377
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
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:5209
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2134
#define CONSHDLR_DESC
Definition: cons_knapsack.c:80
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:3298
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:95
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:365
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:72
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8353
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17711
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:595
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:1603
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:1482
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE GUBsetMoveVar(SCIP *scip, SCIP_GUBSET *gubset, SCIP_VAR **vars, int var, int oldgubcons, int newgubcons)
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3306
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:1998
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2496
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:354
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:886
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
static SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18111
#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:17919
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:825
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:12318
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
#define SCIP_MAXSTRLEN
Definition: def.h:302
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3356
public methods for conflict handler plugins and conflict analysis
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:82
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:317
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1758
static void updateWeightSums(SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Longint weightdelta)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2851
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17699
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1695
SCIP_RETCODE SCIPsetConsPropagated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool propagate)
Definition: scip_cons.c:1317
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:1566
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17975
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:18282
static SCIP_RETCODE getLiftingSequenceGUB(SCIP *scip, SCIP_GUBSET *gubset, SCIP_Real *solvals, SCIP_Longint *weights, int *varsC1, int *varsC2, int *varsF, int *varsR, int nvarsC1, int nvarsC2, int nvarsF, int nvarsR, int *gubconsGC1, int *gubconsGC2, int *gubconsGFC1, int *gubconsGR, int *ngubconsGC1, int *ngubconsGC2, int *ngubconsGFC1, int *ngubconsGR, int *ngubconscapexceed, int *maxgubvarssize)
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip_cons.c:687
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
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:104
#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:1470
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1254
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17440
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:155
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:486
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:84
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, SCIP_Bool *redundant, int *nfixedvars, SCIP_Bool usenegatedclique)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4556
#define FALSE
Definition: def.h:96
#define MAX_CLIQUELENGTH
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3023
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11072
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:175
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:89
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10764
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:95
#define SCIPdebug(x)
Definition: pub_message.h:93
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:743
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:1988
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
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:3593
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:86
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8373
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18153
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:54
static void consdataChgWeight(SCIP_CONSDATA *consdata, int item, SCIP_Longint newweight)
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3141
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17609
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:900
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4863
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:8403
public methods for problem variables
#define SCIPhashSix(a, b, c, d, e, f)
Definition: pub_misc.h:531
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:5326
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:97
#define SCIPdebugMessage
Definition: pub_message.h:96
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:229
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18123
static void GUBsetFree(SCIP *scip, SCIP_GUBSET **gubset)
void SCIPselectWeightedDownRealLongRealInt(SCIP_Real *realarray1, SCIP_Longint *longarray, SCIP_Real *realarray3, int *intarray, SCIP_Real *weights, SCIP_Real capacity, int len, int *medianpos)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:5093
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_LONGINT_MAX
Definition: def.h:172
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:575
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:428
public methods for SCIP variables
SCIP_RETCODE SCIPsetConshdlrDelvars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELVARS((*consdelvars)))
Definition: scip_cons.c:756
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8363
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:618
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17304
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
#define SCIPdebugMsg
Definition: scip_message.h:78
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:83
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1486
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:94
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:802
#define DEFAULT_PRESOLUSEHASHING
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8155
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18271
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:208
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2180
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:943
SCIP_Real SCIPepsilon(SCIP *scip)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:52
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:2245
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:17735
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17515
#define DEFAULT_SEPACARDFREQ
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3372
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4265
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:78
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:1242
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:6927
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:17929
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:12226
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:438
SCIP_VAR * w
Definition: circlepacking.c:67
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
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:81
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:117
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:612
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition: nlp.c:1872
void SCIPsortDownPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:53
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:341
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:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4184
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2778
#define SCIPdebugPrintf
Definition: pub_message.h:99
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:363
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:3482
public methods for event handler plugins and event handlers
SCIP_RETCODE SCIPcleanupConssKnapsack(SCIP *scip, SCIP_Bool onlychecked, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1398
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:122
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1025
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:2906
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4443
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1292
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8094
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18185
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8313
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:85
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17260
static SCIP_DECL_CONSACTIVE(consActiveKnapsack)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:366
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3057
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4204
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
#define NULL
Definition: lpi_spx1.cpp:164
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1960
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:210
#define DEFAULT_NEGATEDCLIQUE
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
public methods for problem copies
static void GUBconsFree(SCIP *scip, SCIP_GUBCONS **gubcons)
#define SCIP_CALL(x)
Definition: def.h:393
SCIP_Real SCIPgetLowerbound(SCIP *scip)
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:77
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:61
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18143
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17723
SCIP_VAR * h
Definition: circlepacking.c:68
static SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
#define MAXNCLIQUEVARSCOMP
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2626
GUBVARSTATUS * gubvarsstatus
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:285
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:225
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18175
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8333
#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:250
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:641
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
static SCIP_DECL_CONSEXIT(consExitKnapsack)
static SCIP_RETCODE getLiftingSequence(SCIP *scip, SCIP_Real *solvals, SCIP_Longint *weights, int *varsF, int *varsC2, int *varsR, int nvarsF, int nvarsC2, int nvarsR)
public methods for constraint handler plugins and constraints
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSPRESOL(consPresolKnapsack)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool transformed)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9272
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
public data structures and miscellaneous methods
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18229
static SCIP_RETCODE enlargeMinweights(SCIP *scip, SCIP_Longint **minweightsptr, int *minweightslen, int *minweightssize, int newlen)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1053
#define SCIP_Bool
Definition: def.h:93
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1030
#define MINGAINPERNMINCOMPARISONS
static SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
static SCIP_RETCODE calcCliquepartition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSDATA *consdata, SCIP_Bool normalclique, SCIP_Bool negatedclique)
static SCIP_DECL_CONSPROP(consPropKnapsack)
#define MAXABSVBCOEF
static SCIP_RETCODE superadditiveUpLifting(SCIP *scip, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int ncovervars, int nnoncovervars, SCIP_Longint coverweight, SCIP_Real *liftcoefs, SCIP_Real *cutact)
#define CONSHDLR_DELAYSEPA
Definition: cons_knapsack.c:90
#define DEFAULT_MAXSEPACUTS
SCIP_RETCODE SCIPincludeConshdlrKnapsack(SCIP *scip)
#define DEFAULT_MAXCARDBOUNDDIST
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:670
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18197
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:2482
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
#define MAX(x, y)
Definition: tclique_def.h:92
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:7262
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8114
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11950
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3389
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:1453
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8223
#define DEFAULT_USEGUBS
static SCIP_RETCODE GUBsetCreate(SCIP *scip, SCIP_GUBSET **gubset, int nvars, SCIP_Longint *weights, SCIP_Longint capacity)
#define KNAPSACKRELAX_MAXDELTA
public methods for cuts and aggregation rows
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8293
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8263
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17767
#define MAX_ZEROITEMS_SIZE
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
#define EVENTHDLR_DESC
Definition: cons_knapsack.c:98
#define CONSHDLR_NAME
Definition: cons_knapsack.c:79
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip_nlp.c:921
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8282
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:136
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:91
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:17317
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4357
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:779
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:79
Constraint handler for linear constraints in their most general form, .
int SCIPgetNObjVars(SCIP *scip)
Definition: scip_prob.c:2228
#define IDX(j, d)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2557
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17687
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:18243
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:329
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4633
static SCIP_RETCODE dropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
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:2295
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2000
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:391
public methods for nonlinear relaxation
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:3704
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:18214
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:510
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:65
static SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
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:134
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:8124
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:390
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4576
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:1267
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:414
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:152
SCIP_Bool SCIPisConsCompressionEnabled(SCIP *scip)
Definition: scip_copy.c:660
public methods for the probing mode
constraint handler for cardinality constraints
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1119
static SCIP_Bool checkMinweightidx(SCIP_Longint *weights, SCIP_Longint capacity, int *covervars, int ncovervars, SCIP_Longint coverweight, int minweightidx, int j)
#define DEFAULT_DETECTLOWERBOUND
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:534
public methods for message output
#define HASHSIZE_KNAPSACKCONS
enum GUBConsstatus GUBCONSSTATUS
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:7581
#define MAX_USECLIQUES_SIZE
static SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
static SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1955
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17379
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7481
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1220
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:186
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8343
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:703
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:12286
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:848
#define GUBCONSGROWVALUE
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4619
public methods for message handling
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8283
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:99
#define SCIP_INVALID
Definition: def.h:206
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8273
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2206
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18165
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:85
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:92
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
#define SCIP_Longint
Definition: def.h:171
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:9467
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17599
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:64
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17985
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3367
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17402
void SCIPsortDownRealIntLong(SCIP_Real *realarray, int *intarray, SCIP_Longint *longarray, int len)
static SCIP_RETCODE getFeasibleSet(SCIP *scip, SCIP_CONS *cons, SCIP_SEPA *sepa, SCIP_VAR **vars, int nvars, int ntightened, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Real *solvals, int *covervars, int *noncovervars, int *ncovervars, int *nnoncovervars, SCIP_Longint *coverweight, SCIP_Bool modtransused, SCIP_SOL *sol, SCIP_Bool *cutoff, int *ncuts)
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, int *ndelconss)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
public methods for separators
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:132
static SCIP_RETCODE eventdataFree(SCIP *scip, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE detectRedundantVars(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *nchgcoefs, int *nchgsides, int *naddconss)
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
Definition: scip_cons.c:664
#define USESUPADDLIFT
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:439
#define NMINCOMPARISONS
static SCIP_DECL_CONSTRANS(consTransKnapsack)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3230
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1391
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:462
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPABORT()
Definition: def.h:365
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:230
public methods for global and local (sub)problems
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17451
#define MAXCOVERSIZEITERLEWI
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9031
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1361
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17481
static SCIP_RETCODE changePartitionFeasiblesetvars(SCIP *scip, SCIP_Longint *weights, int *varsC1, int *varsC2, int *nvarsC1, int *nvarsC2)
static SCIP_RETCODE tightenWeightsLift(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, SCIP_Bool *cutoff)
void SCIPsortDownLongPtr(SCIP_Longint *longarray, void **ptrarray, int len)
#define DEFAULT_UPDATECLIQUEPARTITIONS
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8635
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:139
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:5729
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:83
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:71
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1533
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:57
int SCIPgetNSepaRounds(SCIP *scip)
#define DEFAULT_SIMPLIFYINEQUALITIES
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17589
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17415
methods for selecting (weighted) k-medians
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:275
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1217
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
memory allocation routines