Scippy

SCIP

Solving Constraint Integer Programs

cons_knapsack.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */
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 #ifdef WITH_CARDINALITY_UPGRADE
72 #include "scip/cons_cardinality.h"
73 #endif
74 
75 /* constraint handler properties */
76 #define CONSHDLR_NAME "knapsack"
77 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
78 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
79 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
80 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
81 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
82 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
83 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
84  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
85 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
86 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
87 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
88 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
89 
90 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
91 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
92 
93 #define EVENTHDLR_NAME "knapsack"
94 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
95 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
96  | SCIP_EVENTTYPE_UBTIGHTENED \
97  | SCIP_EVENTTYPE_VARFIXED \
98  | SCIP_EVENTTYPE_VARDELETED \
99  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
100 
101 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
103 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
104 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
106 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
107 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
108 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
110 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
111 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
112 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
113 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
114 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
115 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
116  * to best node's dual bound for separating knapsack cuts */
117 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
118 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
119 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
121 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
122 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
124 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
125 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
127 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
128 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
129 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
130  * comparison round */
131 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
132 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
133  * function defining an upper bound and prevent these constraints from
134  * entering the LP */
135 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
136  * function defining a lower bound and prevent these constraints from
137  * entering the LP */
138 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
139 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
141 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
142 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
143 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
144 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
145  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
146 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
147 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
148 #ifdef WITH_CARDINALITY_UPGRADE
149 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
150 #endif
152 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
153 
154 /*
155  * Data structures
156  */
157 
158 /** constraint handler data */
159 struct SCIP_ConshdlrData
160 {
161  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
162  * you have to clear it at the end, exists only in presolving stage */
163  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
164  * you have to clear it at the end, exists only in presolving stage */
165  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
166  * you have to clear it at the end, exists only in presolving stage */
167  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
168  * you have to clear it at the end, exists only in presolving stage */
169  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
170  * you have to clear it at the end, exists only in presolving stage */
171  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
172  * you have to clear it at the end, exists only in presolving stage */
173  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
174  * you have to clear it at the end, exists only in presolving stage */
175  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
176  * you have to clear it at the end, exists only in presolving stage */
177  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
178  * you have to clear it at the end */
179  int ints1size; /**< size of ints1 array */
180  int ints2size; /**< size of ints2 array */
181  int longints1size; /**< size of longints1 array */
182  int longints2size; /**< size of longints2 array */
183  int bools1size; /**< size of bools1 array */
184  int bools2size; /**< size of bools2 array */
185  int bools3size; /**< size of bools3 array */
186  int bools4size; /**< size of bools4 array */
187  int reals1size; /**< size of reals1 array */
188  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
189  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
190  * to best node's dual bound for separating knapsack cuts */
191  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
192  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
193  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
194  int maxsepacuts; /**< maximal number of cuts separated per separation round */
195  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
196  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
197  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
198  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
199  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
200  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
201  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
202  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
203  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
204  * function defining an upper bound and prevent these constraints from
205  * entering the LP */
206  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
207  * function defining a lower bound and prevent these constraints from
208  * entering the LP */
209  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
210  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
211  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
212  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
213 #ifdef WITH_CARDINALITY_UPGRADE
214  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
215  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
216 #endif
217 };
218 
219 
220 /** constraint data for knapsack constraints */
221 struct SCIP_ConsData
222 {
223  SCIP_VAR** vars; /**< variables in knapsack constraint */
224  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
225  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
226  int* cliquepartition; /**< clique indices of the clique partition */
227  int* negcliquepartition; /**< clique indices of the negated clique partition */
228  SCIP_ROW* row; /**< corresponding LP row */
229  SCIP_NLROW* nlrow; /**< corresponding NLP row */
230  int nvars; /**< number of variables in knapsack constraint */
231  int varssize; /**< size of vars, weights, and eventdata arrays */
232  int ncliques; /**< number of cliques in the clique partition */
233  int nnegcliques; /**< number of cliques in the negated clique partition */
234  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
235  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
236  SCIP_Longint capacity; /**< capacity of knapsack */
237  SCIP_Longint weightsum; /**< sum of all weights */
238  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
239  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
240  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
241  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
242  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
243  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
244  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
245  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
246  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
247 };
248 
249 /** event data for bound changes events */
250 struct SCIP_EventData
251 {
252  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
253  SCIP_Longint weight; /**< weight of variable */
254  int filterpos; /**< position of event in variable's event filter */
255 };
256 
257 
258 /** data structure to combine two sorting key values */
259 struct sortkeypair
260 {
261  SCIP_Real key1; /**< first sort key value */
262  SCIP_Real key2; /**< second sort key value */
263 };
264 typedef struct sortkeypair SORTKEYPAIR;
265 
266 /** status of GUB constraint */
267 enum GUBVarstatus
268 {
269  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
270  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
271  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
272  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
273  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
274  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
275 };
276 typedef enum GUBVarstatus GUBVARSTATUS;
278 /** status of variable in GUB constraint */
280 {
281  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
282  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
283  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
284  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
285  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
286  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
287 };
288 typedef enum GUBConsstatus GUBCONSSTATUS;
290 /** data structure of GUB constraints */
292 {
293  int* gubvars; /**< indices of GUB variables in knapsack constraint */
294  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
295  int ngubvars; /**< number of GUB variables */
296  int gubvarssize; /**< size of gubvars array */
297 };
298 typedef struct SCIP_GUBCons SCIP_GUBCONS;
300 /** data structure of a set of GUB constraints */
302 {
303  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
304  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
305  int ngubconss; /**< number of GUB constraints */
306  int nvars; /**< number of variables in knapsack constraint */
307  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
308  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
309 };
310 typedef struct SCIP_GUBSet SCIP_GUBSET;
312 /*
313  * Local methods
314  */
316 /** comparison method for two sorting key pairs */
317 static
318 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
319 {
320  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
321  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
322 
323  if( sortkeypair1->key1 < sortkeypair2->key1 )
324  return -1;
325  else if( sortkeypair1->key1 > sortkeypair2->key1 )
326  return +1;
327  else if( sortkeypair1->key2 < sortkeypair2->key2 )
328  return -1;
329  else if( sortkeypair1->key2 > sortkeypair2->key2 )
330  return +1;
331  else
332  return 0;
333 }
334 
335 /** creates event data */
336 static
338  SCIP* scip, /**< SCIP data structure */
339  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
340  SCIP_CONS* cons, /**< constraint */
341  SCIP_Longint weight /**< weight of variable */
342  )
343 {
344  assert(eventdata != NULL);
346  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
347  (*eventdata)->cons = cons;
348  (*eventdata)->weight = weight;
349 
350  return SCIP_OKAY;
351 }
352 
353 /** frees event data */
354 static
356  SCIP* scip, /**< SCIP data structure */
357  SCIP_EVENTDATA** eventdata /**< pointer to event data */
358  )
359 {
360  assert(eventdata != NULL);
361 
362  SCIPfreeBlockMemory(scip, eventdata);
364  return SCIP_OKAY;
365 }
366 
367 /** sorts items in knapsack with nonincreasing weights */
368 static
369 void sortItems(
370  SCIP_CONSDATA* consdata /**< constraint data */
371  )
372 {
373  assert(consdata != NULL);
374  assert(consdata->nvars == 0 || consdata->vars != NULL);
375  assert(consdata->nvars == 0 || consdata->weights != NULL);
376  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
377  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
378 
379  if( !consdata->sorted )
380  {
381  int pos;
382  int lastcliquenum;
383  int v;
384 
385  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
386  * sorted by first array in non-increasing order via sort template */
388  consdata->weights,
389  (void**)consdata->vars,
390  (void**)consdata->eventdata,
391  consdata->cliquepartition,
392  consdata->negcliquepartition,
393  consdata->nvars);
394 
395  v = consdata->nvars - 1;
396  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
397  while( v >= 0 )
398  {
399  int w = v - 1;
400 
401  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
402  --w;
403 
404  if( v - w > 1 )
405  {
406  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
408  (void**)(&(consdata->vars[w+1])),
409  (void**)(&(consdata->eventdata[w+1])),
410  &(consdata->cliquepartition[w+1]),
411  &(consdata->negcliquepartition[w+1]),
412  SCIPvarComp,
413  v - w);
414  }
415  v = w;
416  }
417 
418  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
419  if( consdata->cliquepartitioned )
420  {
421  lastcliquenum = 0;
422 
423  for( pos = 0; pos < consdata->nvars; ++pos )
424  {
425  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
426  * partition is invalid */
427  if( consdata->cliquepartition[pos] > lastcliquenum )
428  {
429  consdata->cliquepartitioned = FALSE;
430  break;
431  }
432  else if( consdata->cliquepartition[pos] == lastcliquenum )
433  ++lastcliquenum;
434  }
435  }
436  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
437  if( consdata->negcliquepartitioned )
438  {
439  lastcliquenum = 0;
440 
441  for( pos = 0; pos < consdata->nvars; ++pos )
442  {
443  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
444  * partition is invalid */
445  if( consdata->negcliquepartition[pos] > lastcliquenum )
446  {
447  consdata->negcliquepartitioned = FALSE;
448  break;
449  }
450  else if( consdata->negcliquepartition[pos] == lastcliquenum )
451  ++lastcliquenum;
452  }
453  }
454 
455  consdata->sorted = TRUE;
456  }
457 #ifndef NDEBUG
458  {
459  /* check if the weight array is sorted in a non-increasing way */
460  int i;
461  for( i = 0; i < consdata->nvars-1; ++i )
462  assert(consdata->weights[i] >= consdata->weights[i+1]);
463  }
464 #endif
465 }
466 
467 /** calculates a partition of the variables into cliques */
468 static
470  SCIP* scip, /**< SCIP data structure */
471  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
472  SCIP_CONSDATA* consdata, /**< constraint data */
473  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
474  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
475  )
476 {
477  SCIP_Bool ispartitionoutdated;
478  SCIP_Bool isnegpartitionoutdated;
479  assert(consdata != NULL);
480  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
481 
482  /* rerun eventually if number of global cliques increased considerably since last partition */
483  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
484  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
485 
486  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
487  {
488  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
489  consdata->cliquepartitioned = TRUE;
490  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
491  }
492 
493  /* rerun eventually if number of global cliques increased considerably since last negated partition */
494  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
495  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
496 
497  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
498  {
499  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
500  consdata->negcliquepartitioned = TRUE;
501  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
502  }
503  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
504  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
505 
506  return SCIP_OKAY;
507 }
508 
509 /** installs rounding locks for the given variable in the given knapsack constraint */
510 static
512  SCIP* scip, /**< SCIP data structure */
513  SCIP_CONS* cons, /**< knapsack constraint */
514  SCIP_VAR* var /**< variable of constraint entry */
515  )
516 {
517  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
518 
519  return SCIP_OKAY;
520 }
521 
522 /** removes rounding locks for the given variable in the given knapsack constraint */
523 static
525  SCIP* scip, /**< SCIP data structure */
526  SCIP_CONS* cons, /**< knapsack constraint */
527  SCIP_VAR* var /**< variable of constraint entry */
528  )
529 {
530  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
531 
532  return SCIP_OKAY;
533 }
534 
535 /** catches bound change events for variables in knapsack */
536 static
538  SCIP* scip, /**< SCIP data structure */
539  SCIP_CONS* cons, /**< constraint */
540  SCIP_CONSDATA* consdata, /**< constraint data */
541  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
542  )
543 {
544  int i;
546  assert(cons != NULL);
547  assert(consdata != NULL);
548  assert(consdata->nvars == 0 || consdata->vars != NULL);
549  assert(consdata->nvars == 0 || consdata->weights != NULL);
550  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
551 
552  for( i = 0; i < consdata->nvars; i++)
553  {
554  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
555  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
556  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
557  }
558 
559  return SCIP_OKAY;
560 }
561 
562 /** drops bound change events for variables in knapsack */
563 static
565  SCIP* scip, /**< SCIP data structure */
566  SCIP_CONSDATA* consdata, /**< constraint data */
567  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
568  )
569 {
570  int i;
571 
572  assert(consdata != NULL);
573  assert(consdata->nvars == 0 || consdata->vars != NULL);
574  assert(consdata->nvars == 0 || consdata->weights != NULL);
575  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
576 
577  for( i = 0; i < consdata->nvars; i++)
578  {
579  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
580  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
581  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
582  }
583 
584  return SCIP_OKAY;
585 }
586 
587 /** ensures, that vars and vals arrays can store at least num entries */
588 static
590  SCIP* scip, /**< SCIP data structure */
591  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
592  int num, /**< minimum number of entries to store */
593  SCIP_Bool transformed /**< is constraint from transformed problem? */
594  )
595 {
596  assert(consdata != NULL);
597  assert(consdata->nvars <= consdata->varssize);
598 
599  if( num > consdata->varssize )
600  {
601  int newsize;
602 
603  newsize = SCIPcalcMemGrowSize(scip, num);
604  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
605  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
606  if( transformed )
607  {
608  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
609  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
610  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
611  }
612  else
613  {
614  assert(consdata->eventdata == NULL);
615  assert(consdata->cliquepartition == NULL);
616  assert(consdata->negcliquepartition == NULL);
617  }
618  consdata->varssize = newsize;
619  }
620  assert(num <= consdata->varssize);
621 
622  return SCIP_OKAY;
623 }
624 
625 /** updates all weight sums for fixed and unfixed variables */
626 static
627 void updateWeightSums(
628  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
629  SCIP_VAR* var, /**< variable for this weight */
630  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
631  )
632 {
633  assert(consdata != NULL);
634  assert(var != NULL);
636  consdata->weightsum += weightdelta;
637 
638  if( SCIPvarGetLbLocal(var) > 0.5 )
639  consdata->onesweightsum += weightdelta;
640 
641  assert(consdata->weightsum >= 0);
642  assert(consdata->onesweightsum >= 0);
643 }
644 
645 /** creates knapsack constraint data */
646 static
648  SCIP* scip, /**< SCIP data structure */
649  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
650  int nvars, /**< number of variables in knapsack */
651  SCIP_VAR** vars, /**< variables of knapsack */
652  SCIP_Longint* weights, /**< weights of knapsack items */
653  SCIP_Longint capacity /**< capacity of knapsack */
654  )
655 {
656  int v;
657  SCIP_Longint constant;
658 
659  assert(consdata != NULL);
660 
661  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
662 
663  constant = 0L;
664  (*consdata)->vars = NULL;
665  (*consdata)->weights = NULL;
666  (*consdata)->nvars = 0;
667  if( nvars > 0 )
668  {
669  SCIP_VAR** varsbuffer;
670  SCIP_Longint* weightsbuffer;
671  int k;
672 
673  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
674  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
675 
676  k = 0;
677  for( v = 0; v < nvars; ++v )
678  {
679  assert(vars[v] != NULL);
680  assert(SCIPvarIsBinary(vars[v]));
681 
682  /* all weight have to be non negative */
683  assert( weights[v] >= 0 );
684 
685  if( weights[v] > 0 )
686  {
687  /* treat fixed variables as constants if problem compression is enabled */
688  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
689  {
690  /* only if the variable is fixed to 1, we add its weight to the constant */
691  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
692  constant += weights[v];
693  }
694  else
695  {
696  varsbuffer[k] = vars[v];
697  weightsbuffer[k] = weights[v];
698  ++k;
699  }
700  }
701  }
702  assert(k >= 0);
703  assert(constant >= 0);
704 
705  (*consdata)->nvars = k;
706 
707  /* copy the active variables and weights into the constraint data structure */
708  if( k > 0 )
709  {
710  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
711  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
712  }
713 
714  /* free buffer storage */
715  SCIPfreeBufferArray(scip, &weightsbuffer);
716  SCIPfreeBufferArray(scip, &varsbuffer);
717  }
718 
719  (*consdata)->varssize = (*consdata)->nvars;
720  (*consdata)->capacity = capacity - constant;
721  (*consdata)->eventdata = NULL;
722  (*consdata)->cliquepartition = NULL;
723  (*consdata)->negcliquepartition = NULL;
724  (*consdata)->row = NULL;
725  (*consdata)->nlrow = NULL;
726  (*consdata)->weightsum = 0;
727  (*consdata)->onesweightsum = 0;
728  (*consdata)->ncliques = 0;
729  (*consdata)->nnegcliques = 0;
730  (*consdata)->presolvedtiming = 0;
731  (*consdata)->sorted = FALSE;
732  (*consdata)->cliquepartitioned = FALSE;
733  (*consdata)->negcliquepartitioned = FALSE;
734  (*consdata)->ncliqueslastpart = -1;
735  (*consdata)->ncliqueslastnegpart = -1;
736  (*consdata)->merged = FALSE;
737  (*consdata)->cliquesadded = FALSE;
738  (*consdata)->varsdeleted = FALSE;
739  (*consdata)->existmultaggr = FALSE;
740 
741  /* get transformed variables, if we are in the transformed problem */
742  if( SCIPisTransformed(scip) )
743  {
744  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
745 
746  for( v = 0; v < (*consdata)->nvars; v++ )
747  {
748  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
749  assert(var != NULL);
750  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
751  }
752 
753  /* allocate memory for additional data structures */
754  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
755  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
756  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
757  }
758 
759  /* calculate sum of weights and capture variables */
760  for( v = 0; v < (*consdata)->nvars; ++v )
761  {
762  /* calculate sum of weights */
763  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
764 
765  /* capture variables */
766  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
767  }
768  return SCIP_OKAY;
769 }
770 
771 /** frees knapsack constraint data */
772 static
774  SCIP* scip, /**< SCIP data structure */
775  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
776  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
777  )
778 {
779  assert(consdata != NULL);
780  assert(*consdata != NULL);
782  if( (*consdata)->row != NULL )
783  {
784  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
785  }
786  if( (*consdata)->nlrow != NULL )
787  {
788  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
789  }
790  if( (*consdata)->eventdata != NULL )
791  {
792  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
793  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
794  }
795  if( (*consdata)->negcliquepartition != NULL )
796  {
797  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
798  }
799  if( (*consdata)->cliquepartition != NULL )
800  {
801  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
802  }
803  if( (*consdata)->vars != NULL )
804  {
805  int v;
806 
807  /* release variables */
808  for( v = 0; v < (*consdata)->nvars; v++ )
809  {
810  assert((*consdata)->vars[v] != NULL);
811  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
812  }
813 
814  assert( (*consdata)->weights != NULL );
815  assert( (*consdata)->varssize > 0 );
816  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
817  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
818  }
819 
820  SCIPfreeBlockMemory(scip, consdata);
821 
822  return SCIP_OKAY;
823 }
824 
825 /** changes a single weight in knapsack constraint data */
826 static
827 void consdataChgWeight(
828  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
829  int item, /**< item number */
830  SCIP_Longint newweight /**< new weight of item */
831  )
832 {
833  SCIP_Longint oldweight;
834  SCIP_Longint weightdiff;
836  assert(consdata != NULL);
837  assert(0 <= item && item < consdata->nvars);
838 
839  oldweight = consdata->weights[item];
840  weightdiff = newweight - oldweight;
841  consdata->weights[item] = newweight;
842 
843  /* update weight sums for all and fixed variables */
844  updateWeightSums(consdata, consdata->vars[item], weightdiff);
845 
846  if( consdata->eventdata != NULL )
847  {
848  assert(consdata->eventdata[item] != NULL);
849  assert(consdata->eventdata[item]->weight == oldweight);
850  consdata->eventdata[item]->weight = newweight;
851  }
852 
853  consdata->presolvedtiming = 0;
854  consdata->sorted = FALSE;
855 
856  /* recalculate cliques extraction after a weight was increased */
857  if( oldweight < newweight )
858  {
859  consdata->cliquesadded = FALSE;
860  }
861 }
862 
863 /** creates LP row corresponding to knapsack constraint */
864 static
866  SCIP* scip, /**< SCIP data structure */
867  SCIP_CONS* cons /**< knapsack constraint */
868  )
869 {
870  SCIP_CONSDATA* consdata;
871  int i;
872 
873  consdata = SCIPconsGetData(cons);
874  assert(consdata != NULL);
875  assert(consdata->row == NULL);
876 
877  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
878  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
880 
881  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
882  for( i = 0; i < consdata->nvars; ++i )
883  {
884  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
885  }
886  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
887 
888  return SCIP_OKAY;
889 }
890 
891 /** adds linear relaxation of knapsack constraint to the LP */
892 static
894  SCIP* scip, /**< SCIP data structure */
895  SCIP_CONS* cons, /**< knapsack constraint */
896  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
897  )
898 {
899  SCIP_CONSDATA* consdata;
900 
901  assert( cutoff != NULL );
902  *cutoff = FALSE;
903 
904  consdata = SCIPconsGetData(cons);
905  assert(consdata != NULL);
906 
907  if( consdata->row == NULL )
908  {
909  SCIP_CALL( createRelaxation(scip, cons) );
910  }
911  assert(consdata->row != NULL);
912 
913  /* insert LP row as cut */
914  if( !SCIProwIsInLP(consdata->row) )
915  {
916  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
917  SCIPconsGetName(cons), consdata->capacity);
918  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
919  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
920  }
921 
922  return SCIP_OKAY;
923 }
924 
925 /** adds knapsack constraint as row to the NLP, if not added yet */
926 static
928  SCIP* scip, /**< SCIP data structure */
929  SCIP_CONS* cons /**< knapsack constraint */
930  )
931 {
932  SCIP_CONSDATA* consdata;
933 
934  assert(SCIPisNLPConstructed(scip));
936  /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
937  if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
938  return SCIP_OKAY;
939 
940  consdata = SCIPconsGetData(cons);
941  assert(consdata != NULL);
942 
943  if( consdata->nlrow == NULL )
944  {
945  SCIP_Real* coefs;
946  int i;
947 
948  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
949  for( i = 0; i < consdata->nvars; ++i )
950  coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
951 
952  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
953  consdata->nvars, consdata->vars, coefs, NULL,
954  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
955 
956  assert(consdata->nlrow != NULL);
957 
958  SCIPfreeBufferArray(scip, &coefs);
959  }
960 
961  if( !SCIPnlrowIsInNLP(consdata->nlrow) )
962  {
963  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
964  }
965 
966  return SCIP_OKAY;
967 }
968 
969 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
970 static
972  SCIP* scip, /**< SCIP data structure */
973  SCIP_CONS* cons, /**< constraint to check */
974  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
975  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
976  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
977  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
978  )
979 {
980  SCIP_CONSDATA* consdata;
981 
982  assert(violated != NULL);
983 
984  consdata = SCIPconsGetData(cons);
985  assert(consdata != NULL);
986 
987  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
988  SCIPconsGetName(cons), (void*)sol, checklprows);
989 
990  *violated = FALSE;
991 
992  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
993  {
994  SCIP_Real sum;
995  SCIP_Longint integralsum;
996  SCIP_Bool ishuge;
997  SCIP_Real absviol;
998  SCIP_Real relviol;
999  int v;
1000 
1001  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1002  * enforcement
1003  */
1004  if( sol == NULL )
1005  {
1006  SCIP_CALL( SCIPincConsAge(scip, cons) );
1007  }
1008 
1009  sum = 0.0;
1010  integralsum = 0;
1011  /* we perform a more exact comparison if the capacity does not exceed the huge value */
1012  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
1013  {
1014  ishuge = TRUE;
1015 
1016  /* sum over all weight times the corresponding solution value */
1017  for( v = consdata->nvars - 1; v >= 0; --v )
1018  {
1019  assert(SCIPvarIsBinary(consdata->vars[v]));
1020  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1021  }
1022  }
1023  else
1024  {
1025  ishuge = FALSE;
1026 
1027  /* sum over all weight for which the variable has a solution value of 1 in feastol */
1028  for( v = consdata->nvars - 1; v >= 0; --v )
1029  {
1030  assert(SCIPvarIsBinary(consdata->vars[v]));
1031 
1032  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
1033  integralsum += consdata->weights[v];
1034  }
1035  }
1036 
1037  /* calculate constraint violation and update it in solution */
1038  absviol = ishuge ? sum : (SCIP_Real)integralsum;
1039  absviol -= consdata->capacity;
1040  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
1041  if( sol != NULL )
1042  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1043 
1044  if( SCIPisFeasPositive(scip, absviol) )
1045  {
1046  *violated = TRUE;
1047 
1048  /* only reset constraint age if we are in enforcement */
1049  if( sol == NULL )
1050  {
1051  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1052  }
1053 
1054  if( printreason )
1055  {
1056  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1057 
1058  SCIPinfoMessage(scip, NULL, ";\n");
1059  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1060  }
1061  }
1062  }
1063 
1064  return SCIP_OKAY;
1065 }
1066 
1067 /* IDX computes the integer index for the optimal solution array */
1068 #define IDX(j,d) ((j)*(intcap)+(d))
1069 
1070 /** solves knapsack problem in maximization form exactly using dynamic programming;
1071  * if needed, one can provide arrays to store all selected items and all not selected items
1072  *
1073  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1074  *
1075  * @note the algorithm will first compute a greedy solution and terminate
1076  * if the greedy solution is proven to be optimal.
1077  * The dynamic programming algorithm runs with a time and space complexity
1078  * of O(nitems * capacity).
1079  *
1080  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1081  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1082  * to be checked whether they are faster and whether they can reconstruct the solution.
1083  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1084  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1085  * This could be implemented, however, it would be technically a bit cumbersome,
1086  * since one needs the greedy solution and the LP-value for this.
1087  * This is currently only available after the redundant items have already been sorted out.
1088  */
1090  SCIP* scip, /**< SCIP data structure */
1091  int nitems, /**< number of available items */
1092  SCIP_Longint* weights, /**< item weights */
1093  SCIP_Real* profits, /**< item profits */
1094  SCIP_Longint capacity, /**< capacity of knapsack */
1095  int* items, /**< item numbers */
1096  int* solitems, /**< array to store items in solution, or NULL */
1097  int* nonsolitems, /**< array to store items not in solution, or NULL */
1098  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1099  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1100  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1101  SCIP_Bool* success /**< pointer to store if an error occured during solving
1102  * (normally a memory problem) */
1103  )
1104 {
1105  SCIP_RETCODE retcode;
1106  SCIP_Real* tempsort;
1107  SCIP_Real* optvalues;
1108  int intcap;
1109  int d;
1110  int j;
1111  int greedymedianpos;
1112  SCIP_Longint weightsum;
1113  int* myitems;
1114  SCIP_Longint* myweights;
1115  SCIP_Real* realweights;
1116  int* allcurrminweight;
1117  SCIP_Real* myprofits;
1118  int nmyitems;
1119  SCIP_Longint gcd;
1120  SCIP_Longint minweight;
1121  SCIP_Longint maxweight;
1122  int currminweight;
1123  SCIP_Longint greedysolweight;
1124  SCIP_Real greedysolvalue;
1125  SCIP_Real greedyupperbound;
1126  SCIP_Bool eqweights;
1127  SCIP_Bool intprofits;
1128 
1129  assert(weights != NULL);
1130  assert(profits != NULL);
1131  assert(capacity >= 0);
1132  assert(items != NULL);
1133  assert(nitems >= 0);
1134  assert(success != NULL);
1135 
1136  *success = TRUE;
1137 
1138 #ifndef NDEBUG
1139  for( j = nitems - 1; j >= 0; --j )
1140  assert(weights[j] >= 0);
1141 #endif
1142 
1143  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1144 
1145  /* initializing solution value */
1146  if( solval != NULL )
1147  *solval = 0.0;
1148 
1149  /* init solution information */
1150  if( solitems != NULL )
1151  {
1152  assert(items != NULL);
1153  assert(nsolitems != NULL);
1154  assert(nonsolitems != NULL);
1155  assert(nnonsolitems != NULL);
1156 
1157  *nnonsolitems = 0;
1158  *nsolitems = 0;
1159  }
1160 
1161  /* allocate temporary memory */
1162  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1163  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1164  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1165  nmyitems = 0;
1166  weightsum = 0;
1167  minweight = SCIP_LONGINT_MAX;
1168  maxweight = 0;
1169 
1170  /* remove unnecessary items */
1171  for( j = 0; j < nitems; ++j )
1172  {
1173  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1174 
1175  /* item does not fit */
1176  if( weights[j] > capacity )
1177  {
1178  if( solitems != NULL )
1179  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1180  }
1181  /* item is not profitable */
1182  else if( profits[j] <= 0.0 )
1183  {
1184  if( solitems != NULL )
1185  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1186  }
1187  /* item always fits */
1188  else if( weights[j] == 0 )
1189  {
1190  if( solitems != NULL )
1191  solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1192 
1193  if( solval != NULL )
1194  *solval += profits[j];
1195  }
1196  /* all important items */
1197  else
1198  {
1199  myweights[nmyitems] = weights[j];
1200  myprofits[nmyitems] = profits[j];
1201  myitems[nmyitems] = items[j];
1202 
1203  /* remember smallest item */
1204  if( myweights[nmyitems] < minweight )
1205  minweight = myweights[nmyitems];
1206 
1207  /* remember bigest item */
1208  if( myweights[nmyitems] > maxweight )
1209  maxweight = myweights[nmyitems];
1210 
1211  weightsum += myweights[nmyitems];
1212  ++nmyitems;
1213  }
1214  }
1215 
1216  intprofits = TRUE;
1217  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1218  for( j = 0; j < nmyitems && intprofits; ++j )
1219  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1220 
1221  /* if no item is left then goto end */
1222  if( nmyitems == 0 )
1223  {
1224  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1225 
1226  goto TERMINATE;
1227  }
1228 
1229  /* if all items fit, we also do not need to do the expensive stuff later on */
1230  if( weightsum > 0 && weightsum <= capacity )
1231  {
1232  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1233 
1234  for( j = nmyitems - 1; j >= 0; --j )
1235  {
1236  if( solitems != NULL )
1237  solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1238 
1239  if( solval != NULL )
1240  *solval += myprofits[j];
1241  }
1242 
1243  goto TERMINATE;
1244  }
1245 
1246  assert(0 < minweight && minweight <= capacity );
1247  assert(0 < maxweight && maxweight <= capacity);
1248 
1249  /* make weights relatively prime */
1250  eqweights = TRUE;
1251  if( maxweight > 1 )
1252  {
1253  /* determine greatest common divisor */
1254  gcd = myweights[nmyitems - 1];
1255  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1256  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1257 
1258  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1259 
1260  /* divide by greatest common divisor */
1261  if( gcd > 1 )
1262  {
1263  for( j = nmyitems - 1; j >= 0; --j )
1264  {
1265  myweights[j] /= gcd;
1266  eqweights = eqweights && (myweights[j] == 1);
1267  }
1268  capacity /= gcd;
1269  minweight /= gcd;
1270  }
1271  else
1272  eqweights = FALSE;
1273  }
1274  assert(minweight <= capacity);
1275 
1276  /* if only one item fits, then take the best */
1277  if( minweight > capacity / 2 )
1278  {
1279  int p;
1280 
1281  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1282 
1283  p = nmyitems - 1;
1284 
1285  /* find best item */
1286  for( j = nmyitems - 2; j >= 0; --j )
1287  {
1288  if( myprofits[j] > myprofits[p] )
1289  p = j;
1290  }
1291 
1292  /* update solution information */
1293  if( solitems != NULL )
1294  {
1295  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1296 
1297  solitems[(*nsolitems)++] = myitems[p];
1298  for( j = nmyitems - 1; j >= 0; --j )
1299  {
1300  if( j != p )
1301  nonsolitems[(*nnonsolitems)++] = myitems[j];
1302  }
1303  }
1304  /* update solution value */
1305  if( solval != NULL )
1306  *solval += myprofits[p];
1307 
1308  goto TERMINATE;
1309  }
1310 
1311  /* if all items have the same weight, then take the best */
1312  if( eqweights )
1313  {
1314  SCIP_Real addval = 0.0;
1315 
1316  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1317 
1318  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1319 
1320  /* update solution information */
1321  if( solitems != NULL || solval != NULL )
1322  {
1323  SCIP_Longint i;
1324 
1325  /* if all items would fit we had handled this case before */
1326  assert((SCIP_Longint) nmyitems > capacity);
1327  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1328 
1329  /* take the first best items into the solution */
1330  for( i = capacity - 1; i >= 0; --i )
1331  {
1332  if( solitems != NULL )
1333  solitems[(*nsolitems)++] = myitems[i];
1334  addval += myprofits[i];
1335  }
1336 
1337  if( solitems != NULL )
1338  {
1339  /* the rest are not in the solution */
1340  for( i = nmyitems - 1; i >= capacity; --i )
1341  nonsolitems[(*nnonsolitems)++] = myitems[i];
1342  }
1343  }
1344  /* update solution value */
1345  if( solval != NULL )
1346  {
1347  assert(addval > 0.0);
1348  *solval += addval;
1349  }
1350 
1351  goto TERMINATE;
1352  }
1353 
1354  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1355 
1356  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1357  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1358  */
1359  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1360  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1361 
1362  for( j = 0; j < nmyitems; ++j )
1363  {
1364  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1365  realweights[j] = (SCIP_Real)myweights[j];
1366  }
1367 
1368  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1369  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1370 
1371  SCIPfreeBufferArray(scip, &realweights);
1372  SCIPfreeBufferArray(scip, &tempsort);
1373 
1374  /* initialize values for greedy solution information */
1375  greedysolweight = 0;
1376  greedysolvalue = 0.0;
1377 
1378  /* determine greedy solution */
1379  for( j = 0; j < greedymedianpos; ++j )
1380  {
1381  assert(myweights[j] <= capacity);
1382 
1383  /* update greedy solution weight and value */
1384  greedysolweight += myweights[j];
1385  greedysolvalue += myprofits[j];
1386  }
1387 
1388  assert(0 < greedysolweight && greedysolweight <= capacity);
1389  assert(greedysolvalue > 0.0);
1390 
1391  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1392  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1393  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1394  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1395  if( intprofits )
1396  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1397  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1398  {
1399  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1400 
1401  /* update solution information */
1402  if( solitems != NULL )
1403  {
1404  int l;
1405 
1406  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1407 
1408  /* collect items */
1409  for( l = 0; l < j; ++l )
1410  solitems[(*nsolitems)++] = myitems[l];
1411  for ( ; l < nmyitems; ++l )
1412  nonsolitems[(*nnonsolitems)++] = myitems[l];
1413  }
1414  /* update solution value */
1415  if( solval != NULL )
1416  {
1417  assert(greedysolvalue > 0.0);
1418  *solval += greedysolvalue;
1419  }
1420 
1421  goto TERMINATE;
1422  }
1423 
1424  /* in the following table we do not need the first minweight columns */
1425  capacity -= (minweight - 1);
1426 
1427  /* we can only handle integers */
1428  if( capacity >= INT_MAX )
1429  {
1430  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1431 
1432  *success = FALSE;
1433  goto TERMINATE;
1434  }
1435  assert(capacity < INT_MAX);
1436 
1437  intcap = (int)capacity;
1438  assert(intcap >= 0);
1439  assert(nmyitems > 0);
1440  assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1441 
1442  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1443  * computing the size for the allocation
1444  */
1445  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*/
1446  {
1447  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1448 
1449  *success = FALSE;
1450  goto TERMINATE;
1451  }
1452 
1453  /* allocate temporary memory and check for memory exceedance */
1454  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1455  if( retcode == SCIP_NOMEMORY )
1456  {
1457  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1458 
1459  *success = FALSE;
1460  goto TERMINATE;
1461  }
1462  else
1463  {
1464  SCIP_CALL( retcode );
1465  }
1466 
1467  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1468 
1469  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1470  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1471  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1472  * 'nmyitem' values
1473  */
1474  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1475  assert(myweights[0] - minweight < INT_MAX);
1476  currminweight = (int) (myweights[0] - minweight);
1477  allcurrminweight[0] = currminweight;
1478 
1479  /* fills first row of dynamic programming table with optimal values */
1480  for( d = currminweight; d < intcap; ++d )
1481  optvalues[d] = myprofits[0];
1482 
1483  /* fills dynamic programming table with optimal values */
1484  for( j = 1; j < nmyitems; ++j )
1485  {
1486  int intweight;
1487 
1488  /* compute important part of weight, which will be represented in the table */
1489  intweight = (int)(myweights[j] - minweight);
1490  assert(0 <= intweight && intweight < intcap);
1491 
1492  /* copy all nonzeros from row above */
1493  for( d = currminweight; d < intweight && d < intcap; ++d )
1494  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1495 
1496  /* update corresponding row */
1497  for( d = intweight; d < intcap; ++d )
1498  {
1499  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1500  if( d < currminweight )
1501  optvalues[IDX(j,d)] = myprofits[j];
1502  else
1503  {
1504  SCIP_Real sumprofit;
1505 
1506  if( d - myweights[j] < currminweight )
1507  sumprofit = myprofits[j];
1508  else
1509  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1510 
1511  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1512  }
1513  }
1514 
1515  /* update currminweight */
1516  if( intweight < currminweight )
1517  currminweight = intweight;
1518 
1519  allcurrminweight[j] = currminweight;
1520  }
1521 
1522  /* update optimal solution by following the table */
1523  if( solitems != NULL )
1524  {
1525  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1526  d = intcap - 1;
1527 
1528  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1529 
1530  /* insert all items in (non-) solution vector */
1531  for( j = nmyitems - 1; j > 0; --j )
1532  {
1533  /* if the following condition holds this means all remaining items does not fit anymore */
1534  if( d < allcurrminweight[j] )
1535  {
1536  /* we cannot have exceeded our capacity */
1537  assert((SCIP_Longint) d >= -minweight);
1538  break;
1539  }
1540 
1541  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1542  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1543  {
1544  solitems[(*nsolitems)++] = myitems[j];
1545 
1546  /* check that we do not have an underflow */
1547  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1548  d = (int)(d - myweights[j]);
1549  }
1550  /* collect non-solution items */
1551  else
1552  nonsolitems[(*nnonsolitems)++] = myitems[j];
1553  }
1554 
1555  /* insert remaining items */
1556  if( d >= allcurrminweight[j] )
1557  {
1558  assert(j == 0);
1559  solitems[(*nsolitems)++] = myitems[j];
1560  }
1561  else
1562  {
1563  assert(j >= 0);
1564  assert(d < allcurrminweight[j]);
1565 
1566  for( ; j >= 0; --j )
1567  nonsolitems[(*nnonsolitems)++] = myitems[j];
1568  }
1569 
1570  assert(*nsolitems + *nnonsolitems == nitems);
1571  }
1572 
1573  /* update solution value */
1574  if( solval != NULL )
1575  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1576  SCIPfreeBufferArray(scip, &allcurrminweight);
1577 
1578  /* free all temporary memory */
1579  SCIPfreeBufferArray(scip, &optvalues);
1580 
1581  TERMINATE:
1582  SCIPfreeBufferArray(scip, &myitems);
1583  SCIPfreeBufferArray(scip, &myprofits);
1584  SCIPfreeBufferArray(scip, &myweights);
1585 
1586  return SCIP_OKAY;
1587 }
1588 
1589 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1590  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1591  * selected items
1592  */
1594  SCIP* scip, /**< SCIP data structure */
1595  int nitems, /**< number of available items */
1596  SCIP_Longint* weights, /**< item weights */
1597  SCIP_Real* profits, /**< item profits */
1598  SCIP_Longint capacity, /**< capacity of knapsack */
1599  int* items, /**< item numbers */
1600  int* solitems, /**< array to store items in solution, or NULL */
1601  int* nonsolitems, /**< array to store items not in solution, or NULL */
1602  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1603  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1604  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1605  )
1606 {
1607  SCIP_Real* tempsort;
1608  SCIP_Longint solitemsweight;
1609  SCIP_Real* realweights;
1610  int j;
1611  int criticalindex;
1612 
1613  assert(weights != NULL);
1614  assert(profits != NULL);
1615  assert(capacity >= 0);
1616  assert(items != NULL);
1617  assert(nitems >= 0);
1618 
1619  if( solitems != NULL )
1620  {
1621  *nsolitems = 0;
1622  *nnonsolitems = 0;
1623  }
1624  if( solval != NULL )
1625  *solval = 0.0;
1626 
1627  /* initialize data for median search */
1628  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1629  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1630  for( j = nitems - 1; j >= 0; --j )
1631  {
1632  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1633  realweights[j] = (SCIP_Real)weights[j];
1634  }
1635 
1636  /* partially sort indices such that all elements that are larger than the break item appear first */
1637  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1638 
1639  /* selects items as long as they fit into the knapsack */
1640  solitemsweight = 0;
1641  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1642  {
1643  if( solitems != NULL )
1644  solitems[(*nsolitems)++] = items[j];
1645 
1646  if( solval != NULL )
1647  (*solval) += profits[j];
1648  solitemsweight += weights[j];
1649  }
1650  if ( solitems != NULL )
1651  {
1652  for( ; j < nitems; j++ )
1653  nonsolitems[(*nnonsolitems)++] = items[j];
1654  }
1655 
1656  SCIPfreeBufferArray(scip, &realweights);
1657  SCIPfreeBufferArray(scip, &tempsort);
1658 
1659  return SCIP_OKAY;
1660 }
1661 
1662 #ifdef SCIP_DEBUG
1663 /** prints all nontrivial GUB constraints and their LP solution values */
1664 static
1665 void GUBsetPrint(
1666  SCIP* scip, /**< SCIP data structure */
1667  SCIP_GUBSET* gubset, /**< GUB set data structure */
1668  SCIP_VAR** vars, /**< variables in knapsack constraint */
1669  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1670  )
1671 {
1672  int nnontrivialgubconss;
1673  int c;
1674 
1675  nnontrivialgubconss = 0;
1676 
1677  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1678 
1679  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1680  for( c = 0; c < gubset->ngubconss; c++ )
1681  {
1682  SCIP_Real gubsolval;
1683 
1684  assert(gubset->gubconss[c]->ngubvars >= 0);
1685 
1686  /* nontrivial GUB */
1687  if( gubset->gubconss[c]->ngubvars > 1 )
1688  {
1689  int v;
1690 
1691  gubsolval = 0.0;
1692  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1693 
1694  /* print GUB var */
1695  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1696  {
1697  int currentvar;
1698 
1699  currentvar = gubset->gubconss[c]->gubvars[v];
1700  if( solvals != NULL )
1701  {
1702  gubsolval += solvals[currentvar];
1703  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1704  }
1705  else
1706  {
1707  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1708  }
1709  }
1710 
1711  /* check whether LP solution satisfies the GUB constraint */
1712  if( solvals != NULL )
1713  {
1714  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1715  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1716  }
1717  else
1718  {
1719  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1720  }
1721  nnontrivialgubconss++;
1722  }
1723  }
1724 
1725  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1726 }
1727 #endif
1728 
1729 /** creates an empty GUB constraint */
1730 static
1732  SCIP* scip, /**< SCIP data structure */
1733  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1734  )
1735 {
1736  assert(scip != NULL);
1737  assert(gubcons != NULL);
1738 
1739  /* allocate memory for GUB constraint data structures */
1740  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1741  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1742  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1743  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1744 
1745  (*gubcons)->ngubvars = 0;
1746 
1747  return SCIP_OKAY;
1748 }
1749 
1750 /** frees GUB constraint */
1751 static
1752 void GUBconsFree(
1753  SCIP* scip, /**< SCIP data structure */
1754  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1755  )
1756 {
1757  assert(scip != NULL);
1758  assert(gubcons != NULL);
1759  assert((*gubcons)->gubvars != NULL);
1760  assert((*gubcons)->gubvarsstatus != NULL);
1761 
1762  /* free allocated memory */
1763  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1764  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1765  SCIPfreeBuffer(scip, gubcons);
1766 }
1767 
1768 /** adds variable to given GUB constraint */
1769 static
1771  SCIP* scip, /**< SCIP data structure */
1772  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1773  int var /**< index of given variable in knapsack constraint */
1774  )
1775 {
1776  assert(scip != NULL);
1777  assert(gubcons != NULL);
1778  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1779  assert(gubcons->gubvars != NULL);
1780  assert(gubcons->gubvarsstatus != NULL);
1781  assert(var >= 0);
1782 
1783  /* add variable to GUB constraint */
1784  gubcons->gubvars[gubcons->ngubvars] = var;
1785  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1786  gubcons->ngubvars++;
1787 
1788  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1789  if( gubcons->ngubvars == gubcons->gubvarssize )
1790  {
1791  int newlen;
1792 
1793  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1794  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1795  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1796 
1797  gubcons->gubvarssize = newlen;
1798  }
1799 
1800  return SCIP_OKAY;
1801 }
1802 
1803 /** deletes variable from its current GUB constraint */
1804 static
1806  SCIP* scip, /**< SCIP data structure */
1807  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1808  int var, /**< index of given variable in knapsack constraint */
1809  int gubvarsidx /**< index of the variable in its current GUB constraint */
1810  )
1811 {
1812  assert(scip != NULL);
1813  assert(gubcons != NULL);
1814  assert(var >= 0);
1815  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1816  assert(gubcons->ngubvars >= gubvarsidx+1);
1817  assert(gubcons->gubvars[gubvarsidx] == var);
1818 
1819  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1820  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1821  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1822  gubcons->ngubvars--;
1823 
1824  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1825  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1826  {
1827  int newlen;
1828 
1829  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1830 
1831  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1832  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1833 
1834  gubcons->gubvarssize = newlen;
1835  }
1836 
1837  return SCIP_OKAY;
1838 }
1839 
1840 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1841 static
1843  SCIP* scip, /**< SCIP data structure */
1844  SCIP_GUBSET* gubset, /**< GUB set data structure */
1845  SCIP_VAR** vars, /**< variables in knapsack constraint */
1846  int var, /**< index of given variable in knapsack constraint */
1847  int oldgubcons, /**< index of old GUB constraint of given variable */
1848  int newgubcons /**< index of new GUB constraint of given variable */
1849  )
1851  int oldgubvaridx;
1852  int replacevar;
1853  int j;
1854 
1855  assert(scip != NULL);
1856  assert(gubset != NULL);
1857  assert(var >= 0);
1858  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1859  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1860  assert(oldgubcons != newgubcons);
1861  assert(gubset->gubconssidx[var] == oldgubcons);
1862  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1863  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1864 
1865  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1866 
1867  oldgubvaridx = gubset->gubvarsidx[var];
1868 
1869  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1870  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1871 
1872  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1873  * replacement variable is given by old position of the deleted variable
1874  */
1875  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1876  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1877  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1878 
1879  /* add variable to the end of new GUB constraint */
1880  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1881  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1882 
1883  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1884  gubset->gubconssidx[var] = newgubcons;
1885  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1886 
1887  /* delete old GUB constraint if it became empty */
1888  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1889  {
1890  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1891 #ifdef SCIP_DEBUG
1892  GUBsetPrint(scip, gubset, vars, NULL);
1893 #endif
1894 
1895  /* free old GUB constraint */
1896  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1897 
1898  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1899  if( oldgubcons != gubset->ngubconss-1 )
1900  {
1901  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1902  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1903 
1904  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1905  * replacement GUB is given by old position of the deleted GUB
1906  */
1907  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1908  {
1909  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1910  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1911  }
1912  }
1913 
1914  /* update number of GUB constraints */
1915  gubset->ngubconss--;
1916 
1917  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1918  * (because it was at the end of the GUB constraint array)
1919  */
1920  assert(gubset->gubconssidx[var] == newgubcons
1921  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1922  }
1923 #ifndef NDEBUG
1924  else
1925  assert(gubset->gubconssidx[var] == newgubcons);
1926 #endif
1927 
1928  return SCIP_OKAY;
1929 }
1930 
1931 /** swaps two variables in the same GUB constraint */
1932 static
1933 void GUBsetSwapVars(
1934  SCIP* scip, /**< SCIP data structure */
1935  SCIP_GUBSET* gubset, /**< GUB set data structure */
1936  int var1, /**< first variable to be swapped */
1937  int var2 /**< second variable to be swapped */
1938  )
1939 {
1940  int gubcons;
1941  int var1idx;
1942  GUBVARSTATUS var1status;
1943  int var2idx;
1944  GUBVARSTATUS var2status;
1945 
1946  assert(scip != NULL);
1947  assert(gubset != NULL);
1948 
1949  gubcons = gubset->gubconssidx[var1];
1950  assert(gubcons == gubset->gubconssidx[var2]);
1951 
1952  /* nothing to be done if both variables are the same */
1953  if( var1 == var2 )
1954  return;
1955 
1956  /* swap index and status of variables in GUB constraint */
1957  var1idx = gubset->gubvarsidx[var1];
1958  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1959  var2idx = gubset->gubvarsidx[var2];
1960  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1961 
1962  gubset->gubvarsidx[var1] = var2idx;
1963  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1964  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1965 
1966  gubset->gubvarsidx[var2] = var1idx;
1967  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1968  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1969 }
1970 
1971 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1972 static
1974  SCIP* scip, /**< SCIP data structure */
1975  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1976  int nvars, /**< number of variables in the knapsack constraint */
1977  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1978  SCIP_Longint capacity /**< capacity of knapsack */
1979  )
1980 {
1981  int i;
1982 
1983  assert(scip != NULL);
1984  assert(gubset != NULL);
1985  assert(nvars > 0);
1986  assert(weights != NULL);
1987  assert(capacity >= 0);
1988 
1989  /* allocate memory for GUB set data structures */
1990  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1991  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1992  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1993  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1994  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1995  (*gubset)->ngubconss = nvars;
1996  (*gubset)->nvars = nvars;
1997 
1998  /* initialize the set of GUB constraints */
1999  for( i = 0; i < nvars; i++ )
2000  {
2001  /* assign each variable to a new (trivial) GUB constraint */
2002  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2003  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2004 
2005  /* set status of GUB constraint to initial */
2006  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2007 
2008  (*gubset)->gubconssidx[i] = i;
2009  (*gubset)->gubvarsidx[i] = 0;
2010  assert((*gubset)->gubconss[i]->ngubvars == 1);
2011 
2012  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2013  if( weights[i] > capacity )
2014  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2015  }
2016 
2017  return SCIP_OKAY;
2018 }
2019 
2020 /** frees GUB set data structure */
2021 static
2022 void GUBsetFree(
2023  SCIP* scip, /**< SCIP data structure */
2024  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2025  )
2026 {
2027  int i;
2028 
2029  assert(scip != NULL);
2030  assert(gubset != NULL);
2031  assert((*gubset)->gubconss != NULL);
2032  assert((*gubset)->gubconsstatus != NULL);
2033  assert((*gubset)->gubconssidx != NULL);
2034  assert((*gubset)->gubvarsidx != NULL);
2035 
2036  /* free all GUB constraints */
2037  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2038  {
2039  assert((*gubset)->gubconss[i] != NULL);
2040  GUBconsFree(scip, &(*gubset)->gubconss[i]);
2041  }
2042 
2043  /* free allocated memory */
2044  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2045  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2046  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2047  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2048  SCIPfreeBuffer(scip, gubset);
2049 }
2050 
2051 #ifndef NDEBUG
2052 /** checks whether GUB set data structure is consistent */
2053 static
2055  SCIP* scip, /**< SCIP data structure */
2056  SCIP_GUBSET* gubset, /**< GUB set data structure */
2057  SCIP_VAR** vars /**< variables in the knapsack constraint */
2058  )
2059 {
2060  int i;
2061  int gubconsidx;
2062  int gubvaridx;
2063  SCIP_VAR* var1;
2064  SCIP_VAR* var2;
2065  SCIP_Bool var1negated;
2066  SCIP_Bool var2negated;
2067 
2068  assert(scip != NULL);
2069  assert(gubset != NULL);
2070 
2071  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2072 
2073  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2074  for( i = 0; i < gubset->nvars; i++ )
2075  {
2076  gubconsidx = gubset->gubconssidx[i];
2077  gubvaridx = gubset->gubvarsidx[i];
2078 
2079  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2080  {
2081  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2082  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2083  }
2084  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2085  }
2086 
2087  /* checks for each GUB whether all pairs of its variables have a common clique */
2088  for( i = 0; i < gubset->ngubconss; i++ )
2089  {
2090  int j;
2091 
2092  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2093  {
2094  int k;
2095 
2096  /* get corresponding active problem variable */
2097  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2098  var1negated = FALSE;
2099  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2100 
2101  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2102  {
2103  /* get corresponding active problem variable */
2104  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2105  var2negated = FALSE;
2106  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2107 
2108  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2109  {
2110  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2111  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2112  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2113  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2114  SCIPvarGetName(var1), k,
2115  SCIPvarGetName(var2));
2116  }
2117 
2118  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2119  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2120  }
2121  }
2122  }
2123  SCIPdebugMsg(scip, " --> successful\n");
2124 
2125  return SCIP_OKAY;
2126 }
2127 #endif
2128 
2129 /** calculates a partition of the given set of binary variables into cliques;
2130  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2131  * were assigned to the same clique;
2132  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2133  * the preceding variables was assigned to clique i-1;
2134  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2135  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2136  */
2137 
2138 static
2140  SCIP*const scip, /**< SCIP data structure */
2141  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2142  int const nvars, /**< number of variables in the clique */
2143  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2144  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2145  SCIP_Real* solvals /**< solution values of all given binary variables */
2146  )
2148  SCIP_VAR** tmpvars;
2149  SCIP_VAR** cliquevars;
2150  SCIP_Bool* cliquevalues;
2151  SCIP_Bool* tmpvalues;
2152  int* varseq;
2153  int* sortkeys;
2154  int ncliquevars;
2155  int maxncliquevarscomp;
2156  int nignorevars;
2157  int nvarsused;
2158  int i;
2159 
2160  assert(scip != NULL);
2161  assert(nvars == 0 || vars != NULL);
2162  assert(nvars == 0 || cliquepartition != NULL);
2163  assert(ncliques != NULL);
2164 
2165  if( nvars == 0 )
2166  {
2167  *ncliques = 0;
2168  return SCIP_OKAY;
2169  }
2170 
2171  /* allocate temporary memory for storing the variables of the current clique */
2172  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2173  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2174  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2175  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2176  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2177  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2178 
2179  /* initialize the cliquepartition array with -1 */
2180  /* initialize the tmpvalues array */
2181  for( i = nvars - 1; i >= 0; --i )
2182  {
2183  tmpvalues[i] = TRUE;
2184  cliquepartition[i] = -1;
2185  }
2186 
2187  /* get corresponding active problem variables */
2188  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2189 
2190  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2191  * by nondecreasing number of cliques the variables are in
2192  */
2193  nignorevars = 0;
2194  nvarsused = 0;
2195  for( i = 0; i < nvars; i++ )
2196  {
2197  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2198  {
2199  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2200  varseq[nvars-1-nignorevars] = i;
2201  nignorevars++;
2202  }
2203  else
2204  {
2205  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2206  varseq[nvarsused] = i;
2207  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2208  nvarsused++;
2209  }
2210  }
2211  assert(nvarsused + nignorevars == nvars);
2212 
2213  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2214  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2215 
2216  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2217 
2218  /* calculate the clique partition */
2219  *ncliques = 0;
2220  for( i = 0; i < nvars; ++i )
2221  {
2222  if( cliquepartition[varseq[i]] == -1 )
2223  {
2224  int j;
2225 
2226  /* variable starts a new clique */
2227  cliquepartition[varseq[i]] = *ncliques;
2228  cliquevars[0] = tmpvars[varseq[i]];
2229  cliquevalues[0] = tmpvalues[varseq[i]];
2230  ncliquevars = 1;
2231 
2232  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2233  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2234  */
2235  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2236  {
2237  /* greedily fill up the clique */
2238  for( j = i + 1; j < nvarsused; ++j )
2239  {
2240  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2241  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2242  {
2243  int k;
2244 
2245  /* check if every variable in the actual clique is in clique with the new variable */
2246  for( k = ncliquevars - 1; k >= 0; --k )
2247  {
2248  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2249  cliquevalues[k], TRUE) )
2250  break;
2251  }
2252 
2253  if( k == -1 )
2254  {
2255  /* put the variable into the same clique */
2256  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2257  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2258  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2259  ++ncliquevars;
2260  }
2261  }
2262  }
2263  }
2264 
2265  /* this clique is finished */
2266  ++(*ncliques);
2267  }
2268  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2269 
2270  /* break if we reached the maximal number of comparisons */
2271  if( i * nvars > maxncliquevarscomp )
2272  break;
2273  }
2274  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2275  for( ; i < nvars; ++i )
2276  {
2277  if( cliquepartition[varseq[i]] == -1 )
2278  {
2279  cliquepartition[varseq[i]] = *ncliques;
2280  ++(*ncliques);
2281  }
2282  }
2283 
2284  /* free temporary memory */
2285  SCIPfreeBufferArray(scip, &sortkeys);
2286  SCIPfreeBufferArray(scip, &varseq);
2287  SCIPfreeBufferArray(scip, &tmpvars);
2288  SCIPfreeBufferArray(scip, &tmpvalues);
2289  SCIPfreeBufferArray(scip, &cliquevalues);
2290  SCIPfreeBufferArray(scip, &cliquevars);
2291 
2292  return SCIP_OKAY;
2293 }
2294 
2295 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2296 static
2298  SCIP* scip, /**< SCIP data structure */
2299  SCIP_GUBSET* gubset, /**< GUB set data structure */
2300  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2301  SCIP_Real* solvals /**< solution values of all knapsack variables */
2302  )
2303 {
2304  int* cliquepartition;
2305  int* gubfirstvar;
2306  int ncliques;
2307  int currentgubconsidx;
2308  int newgubconsidx;
2309  int cliqueidx;
2310  int nvars;
2311  int i;
2312 
2313  assert(scip != NULL);
2314  assert(gubset != NULL);
2315  assert(vars != NULL);
2316 
2317  nvars = gubset->nvars;
2318  assert(nvars >= 0);
2319 
2320  /* allocate temporary memory for clique partition */
2321  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2322 
2323  /* compute sophisticated clique partition */
2324  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2325 
2326  /* allocate temporary memory for GUB set data structure */
2327  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2328 
2329  /* translate GUB partition into GUB set data structure */
2330  for( i = 0; i < ncliques; i++ )
2331  {
2332  /* initialize first variable for every GUB */
2333  gubfirstvar[i] = -1;
2334  }
2335  /* move every knapsack variable into GUB defined by clique partition */
2336  for( i = 0; i < nvars; i++ )
2337  {
2338  assert(cliquepartition[i] >= 0);
2339 
2340  cliqueidx = cliquepartition[i];
2341  currentgubconsidx = gubset->gubconssidx[i];
2342  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2343 
2344  /* variable is first element in GUB constraint defined by clique partition */
2345  if( gubfirstvar[cliqueidx] == -1 )
2346  {
2347  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2348  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2349  */
2350  assert(gubset->gubvarsidx[i] == 0);
2351  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2352 
2353  /* remember the first variable found for the current GUB */
2354  gubfirstvar[cliqueidx] = i;
2355  }
2356  /* variable is additional element of GUB constraint defined by clique partition */
2357  else
2358  {
2359  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2360 
2361  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2362  * first variable of this GUB constraint
2363  */
2364  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2365  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2366  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2367 
2368  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2369  }
2370  }
2371 
2372 #ifdef SCIP_DEBUG
2373  /* prints GUB set data structure */
2374  GUBsetPrint(scip, gubset, vars, solvals);
2375 #endif
2376 
2377 #ifndef NDEBUG
2378  /* checks consistency of GUB set data structure */
2379  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2380 #endif
2381 
2382  /* free temporary memory */
2383  SCIPfreeBufferArray(scip, &gubfirstvar);
2384  SCIPfreeBufferArray(scip, &cliquepartition);
2385 
2386  return SCIP_OKAY;
2387 }
2388 
2389 /** 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$
2390  * 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
2391  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2392  */
2393 static
2395  SCIP* scip, /**< SCIP data structure */
2396  SCIP_VAR** vars, /**< variables in knapsack constraint */
2397  int nvars, /**< number of variables in knapsack constraint */
2398  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2399  SCIP_Longint capacity, /**< capacity of knapsack */
2400  SCIP_Real* solvals, /**< solution values of all problem variables */
2401  int* covervars, /**< pointer to store cover variables */
2402  int* noncovervars, /**< pointer to store noncover variables */
2403  int* ncovervars, /**< pointer to store number of cover variables */
2404  int* nnoncovervars, /**< pointer to store number of noncover variables */
2405  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2406  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2407  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2408  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2409  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2410  )
2411 {
2412  SCIP_Longint* transweights;
2413  SCIP_Real* transprofits;
2414  SCIP_Longint transcapacity;
2415  SCIP_Longint fixedonesweight;
2416  SCIP_Longint itemsweight;
2417  SCIP_Bool infeasible;
2418  int* fixedones;
2419  int* fixedzeros;
2420  int* items;
2421  int nfixedones;
2422  int nfixedzeros;
2423  int nitems;
2424  int j;
2425 
2426  assert(scip != NULL);
2427  assert(vars != NULL);
2428  assert(nvars > 0);
2429  assert(weights != NULL);
2430  assert(capacity >= 0);
2431  assert(solvals != NULL);
2432  assert(covervars != NULL);
2433  assert(noncovervars != NULL);
2434  assert(ncovervars != NULL);
2435  assert(nnoncovervars != NULL);
2436  assert(coverweight != NULL);
2437  assert(found != NULL);
2438  assert(ntightened != NULL);
2439  assert(fractional != NULL);
2440 
2441  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2442 
2443  /* allocates temporary memory */
2444  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2445  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2446  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2447  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2448  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2449 
2450  *found = FALSE;
2451  *ncovervars = 0;
2452  *nnoncovervars = 0;
2453  *coverweight = 0;
2454  *fractional = TRUE;
2455 
2456  /* gets the following sets
2457  * N_1 = {j in N : x*_j = 1} (fixedones),
2458  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2459  * N\(N_0 & N_1) (items),
2460  * where x*_j is the solution value of variable x_j
2461  */
2462  nfixedones = 0;
2463  nfixedzeros = 0;
2464  nitems = 0;
2465  fixedonesweight = 0;
2466  itemsweight = 0;
2467  *ntightened = 0;
2468  for( j = 0; j < nvars; j++ )
2469  {
2470  assert(SCIPvarIsBinary(vars[j]));
2471 
2472  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2473  if( weights[j] > capacity )
2474  {
2475  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2476  assert(!infeasible);
2477  (*ntightened)++;
2478  continue;
2479  }
2480 
2481  /* variable x_j has solution value one */
2482  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2483  {
2484  fixedones[nfixedones] = j;
2485  nfixedones++;
2486  fixedonesweight += weights[j];
2487  }
2488  /* variable x_j has solution value zero */
2489  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2490  {
2491  fixedzeros[nfixedzeros] = j;
2492  nfixedzeros++;
2493  }
2494  /* variable x_j has fractional solution value */
2495  else
2496  {
2497  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2498  items[nitems] = j;
2499  nitems++;
2500  itemsweight += weights[j];
2501  }
2502  }
2503  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2504 
2505  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2506  * the separation routine
2507  */
2508  assert(nitems >= 0);
2509  if( nitems == 0 )
2510  {
2511  *fractional = FALSE;
2512  goto TERMINATE;
2513  }
2514  assert(*fractional);
2515 
2516  /* transforms the traditional separation problem (under consideration of the following fixing:
2517  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2518  *
2519  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2520  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2521  * z_j in {0,1}, j in N\(N_0 & N_1)
2522  *
2523  * to a knapsack problem in maximization form by complementing the variables
2524  *
2525  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2526  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2527  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2528  * z_j in {0,1}, j in N\(N_0 & N_1)
2529  */
2530 
2531  /* gets weight and profit of variables in transformed knapsack problem */
2532  for( j = 0; j < nitems; j++ )
2533  {
2534  transweights[j] = weights[items[j]];
2535  transprofits[j] = 1.0 - solvals[items[j]];
2536  }
2537  /* gets capacity of transformed knapsack problem */
2538  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2539 
2540  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2541  * (when variables fixed to zero are not used)
2542  */
2543  if( transcapacity < 0 )
2544  {
2545  assert(!(*found));
2546  goto TERMINATE;
2547  }
2548 
2549  if( modtransused )
2550  {
2551  /* transforms the modified separation problem (under consideration of the following fixing:
2552  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2553  *
2554  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2555  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2556  * z_j in {0,1}, j in N\(N_0 & N_1)
2557  *
2558  * to a knapsack problem in maximization form by complementing the variables
2559  *
2560  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2561  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2562  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2563  * z_j in {0,1}, j in N\(N_0 & N_1)
2564  */
2565 
2566  /* gets weight and profit of variables in modified transformed knapsack problem */
2567  for( j = 0; j < nitems; j++ )
2568  {
2569  transprofits[j] *= weights[items[j]];
2570  assert(SCIPisFeasPositive(scip, transprofits[j]));
2571  }
2572  }
2573 
2574  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2575  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2576  * let z* be the solution, then
2577  * j in C, if z*_j = 0 and
2578  * i in N\C, if z*_j = 1.
2579  */
2580  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2581  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2582  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2583 
2584  /* constructs cover C (sum_{j in C} a_j > a_0) */
2585  for( j = 0; j < *ncovervars; j++ )
2586  {
2587  (*coverweight) += weights[covervars[j]];
2588  }
2589 
2590  /* adds all variables from N_1 to C */
2591  for( j = 0; j < nfixedones; j++ )
2592  {
2593  covervars[*ncovervars] = fixedones[j];
2594  (*ncovervars)++;
2595  (*coverweight) += weights[fixedones[j]];
2596  }
2597 
2598  /* adds all variables from N_0 to N\C */
2599  for( j = 0; j < nfixedzeros; j++ )
2600  {
2601  noncovervars[*nnoncovervars] = fixedzeros[j];
2602  (*nnoncovervars)++;
2603  }
2604  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2605  assert((*coverweight) > capacity);
2606  *found = TRUE;
2607 
2608  TERMINATE:
2609  /* frees temporary memory */
2610  SCIPfreeBufferArray(scip, &items);
2611  SCIPfreeBufferArray(scip, &fixedzeros);
2612  SCIPfreeBufferArray(scip, &fixedones);
2613  SCIPfreeBufferArray(scip, &transprofits);
2614  SCIPfreeBufferArray(scip, &transweights);
2615 
2616  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2617 
2618  return SCIP_OKAY;
2619 }
2620 
2621 #ifndef NDEBUG
2622 /** checks if minweightidx is set correctly
2623  */
2624 static
2626  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2627  SCIP_Longint capacity, /**< capacity of knapsack */
2628  int* covervars, /**< pointer to store cover variables */
2629  int ncovervars, /**< pointer to store number of cover variables */
2630  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2631  int minweightidx, /**< index of variable in cover variables with minimum weight */
2632  int j /**< current index in cover variables */
2633  )
2634 {
2635  SCIP_Longint minweight;
2636  int i;
2637 
2638  assert(weights != NULL);
2639  assert(covervars != NULL);
2640  assert(ncovervars > 0);
2641 
2642  minweight = weights[covervars[minweightidx]];
2643 
2644  /* checks if all cover variables before index j have weight greater than minweight */
2645  for( i = 0; i < j; i++ )
2646  {
2647  assert(weights[covervars[i]] > minweight);
2648  if( weights[covervars[i]] <= minweight )
2649  return FALSE;
2650  }
2651 
2652  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2653  for( i = 0; i < j; i++ )
2654  {
2655  assert(coverweight - weights[covervars[i]] <= capacity);
2656  if( coverweight - weights[covervars[i]] > capacity )
2657  return FALSE;
2658  }
2659  return TRUE;
2660 }
2661 #endif
2662 
2663 
2664 /** 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$,
2665  * 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$
2666  */
2667 static
2669  SCIP* scip, /**< SCIP data structure */
2670  SCIP_Real* solvals, /**< solution values of all problem variables */
2671  int* covervars, /**< cover variables */
2672  int ncovervars, /**< number of cover variables */
2673  int* varsC1, /**< pointer to store variables in C1 */
2674  int* varsC2, /**< pointer to store variables in C2 */
2675  int* nvarsC1, /**< pointer to store number of variables in C1 */
2676  int* nvarsC2 /**< pointer to store number of variables in C2 */
2677  )
2678 {
2679  int j;
2680 
2681  assert(scip != NULL);
2682  assert(ncovervars >= 0);
2683  assert(solvals != NULL);
2684  assert(covervars != NULL);
2685  assert(varsC1 != NULL);
2686  assert(varsC2 != NULL);
2687  assert(nvarsC1 != NULL);
2688  assert(nvarsC2 != NULL);
2689 
2690  *nvarsC1 = 0;
2691  *nvarsC2 = 0;
2692  for( j = 0; j < ncovervars; j++ )
2693  {
2694  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2695 
2696  /* variable has solution value one */
2697  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2698  {
2699  varsC2[*nvarsC2] = covervars[j];
2700  (*nvarsC2)++;
2701  }
2702  /* variable has solution value less than one */
2703  else
2704  {
2705  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2706  varsC1[*nvarsC1] = covervars[j];
2707  (*nvarsC1)++;
2708  }
2709  }
2710  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2711 }
2712 
2713 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2714  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2715  */
2716 static
2718  SCIP* scip, /**< SCIP data structure */
2719  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2720  int* varsC1, /**< pointer to store variables in C1 */
2721  int* varsC2, /**< pointer to store variables in C2 */
2722  int* nvarsC1, /**< pointer to store number of variables in C1 */
2723  int* nvarsC2 /**< pointer to store number of variables in C2 */
2724  )
2726  SCIP_Real* sortkeysC2;
2727  int j;
2728 
2729  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2730  assert(*nvarsC2 > 0);
2731 
2732  /* allocates temporary memory */
2733  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2734 
2735  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2736  for( j = 0; j < *nvarsC2; j++ )
2737  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2738  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2739 
2740  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2741  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2742  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2743  {
2744  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2745  (*nvarsC1)++;
2746  (*nvarsC2)--;
2747  }
2748 
2749  /* frees temporary memory */
2750  SCIPfreeBufferArray(scip, &sortkeysC2);
2751 
2752  return SCIP_OKAY;
2753 }
2754 
2755 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2756 static
2758  SCIP* scip, /**< SCIP data structure */
2759  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2760  int* varsC1, /**< pointer to store variables in C1 */
2761  int* varsC2, /**< pointer to store variables in C2 */
2762  int* nvarsC1, /**< pointer to store number of variables in C1 */
2763  int* nvarsC2 /**< pointer to store number of variables in C2 */
2764  )
2766  SCIP_Real* sortkeysC2;
2767  int j;
2768 
2769  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2770  assert(*nvarsC2 > 0);
2771 
2772  /* allocates temporary memory */
2773  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2774 
2775  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2776  for( j = 0; j < *nvarsC2; j++ )
2777  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2778  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2779 
2780  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2781  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2782  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2783  (*nvarsC1)++;
2784  (*nvarsC2)--;
2785 
2786  /* frees temporary memory */
2787  SCIPfreeBufferArray(scip, &sortkeysC2);
2788 
2789  return SCIP_OKAY;
2790 }
2791 
2792 
2793 /** 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$
2794  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2795  * \f$F = (N \setminus C) \setminus F\f$
2796  */
2797 static
2799  SCIP* scip, /**< SCIP data structure */
2800  SCIP_Real* solvals, /**< solution values of all problem variables */
2801  int* noncovervars, /**< noncover variables */
2802  int nnoncovervars, /**< number of noncover variables */
2803  int* varsF, /**< pointer to store variables in F */
2804  int* varsR, /**< pointer to store variables in R */
2805  int* nvarsF, /**< pointer to store number of variables in F */
2806  int* nvarsR /**< pointer to store number of variables in R */
2807  )
2808 {
2809  int j;
2810 
2811  assert(scip != NULL);
2812  assert(nnoncovervars >= 0);
2813  assert(solvals != NULL);
2814  assert(noncovervars != NULL);
2815  assert(varsF != NULL);
2816  assert(varsR != NULL);
2817  assert(nvarsF != NULL);
2818  assert(nvarsR != NULL);
2819 
2820  *nvarsF = 0;
2821  *nvarsR = 0;
2822 
2823  for( j = 0; j < nnoncovervars; j++ )
2824  {
2825  /* variable has solution value zero */
2826  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2827  {
2828  varsR[*nvarsR] = noncovervars[j];
2829  (*nvarsR)++;
2830  }
2831  /* variable has solution value greater than zero */
2832  else
2833  {
2834  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2835  varsF[*nvarsF] = noncovervars[j];
2836  (*nvarsF)++;
2837  }
2838  }
2839  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2840 }
2841 
2842 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2843  * lifting procedure
2844  */
2845 static
2847  SCIP* scip, /**< SCIP data structure */
2848  SCIP_Real* solvals, /**< solution values of all problem variables */
2849  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2850  int* varsF, /**< pointer to store variables in F */
2851  int* varsC2, /**< pointer to store variables in C2 */
2852  int* varsR, /**< pointer to store variables in R */
2853  int nvarsF, /**< number of variables in F */
2854  int nvarsC2, /**< number of variables in C2 */
2855  int nvarsR /**< number of variables in R */
2856  )
2857 {
2858  SORTKEYPAIR** sortkeypairsF;
2859  SORTKEYPAIR* sortkeypairsFstore;
2860  SCIP_Real* sortkeysC2;
2861  SCIP_Real* sortkeysR;
2862  int j;
2863 
2864  assert(scip != NULL);
2865  assert(solvals != NULL);
2866  assert(weights != NULL);
2867  assert(varsF != NULL);
2868  assert(varsC2 != NULL);
2869  assert(varsR != NULL);
2870  assert(nvarsF >= 0);
2871  assert(nvarsC2 >= 0);
2872  assert(nvarsR >= 0);
2873 
2874  /* allocates temporary memory */
2875  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2876  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2877  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2878  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2879 
2880  /* gets sorting key for variables in F corresponding to the following lifting sequence
2881  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2882  * x*_1 >= x*_2 >= ... >= x*_|F|
2883  * in case of equality uses
2884  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2885  */
2886  for( j = 0; j < nvarsF; j++ )
2887  {
2888  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2889  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2890  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2891  }
2892 
2893  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2894  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2895  */
2896  for( j = 0; j < nvarsC2; j++ )
2897  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2898 
2899  /* gets sorting key for variables in R corresponding to the following lifting sequence
2900  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2901  */
2902  for( j = 0; j < nvarsR; j++ )
2903  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2904 
2905  /* sorts F, C2 and R */
2906  if( nvarsF > 0 )
2907  {
2908  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2909  }
2910  if( nvarsC2 > 0 )
2911  {
2912  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2913  }
2914  if( nvarsR > 0)
2915  {
2916  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2917  }
2918 
2919  /* frees temporary memory */
2920  SCIPfreeBufferArray(scip, &sortkeysR);
2921  SCIPfreeBufferArray(scip, &sortkeysC2);
2922  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2923  SCIPfreeBufferArray(scip, &sortkeypairsF);
2924 
2925  return SCIP_OKAY;
2926 }
2927 
2928 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2929  * for the sequential GUB wise lifting procedure
2930  */
2931 static
2933  SCIP* scip, /**< SCIP data structure */
2934  SCIP_GUBSET* gubset, /**< GUB set data structure */
2935  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2936  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2937  int* varsC1, /**< variables in C1 */
2938  int* varsC2, /**< variables in C2 */
2939  int* varsF, /**< variables in F */
2940  int* varsR, /**< variables in R */
2941  int nvarsC1, /**< number of variables in C1 */
2942  int nvarsC2, /**< number of variables in C2 */
2943  int nvarsF, /**< number of variables in F */
2944  int nvarsR, /**< number of variables in R */
2945  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2946  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2947  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2948  int* gubconsGR, /**< pointer to store GUBs in GR */
2949  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2950  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2951  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2952  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2953  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2954  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2955  )
2956 {
2957  SORTKEYPAIR** sortkeypairsGFC1;
2958  SORTKEYPAIR* sortkeypairsGFC1store;
2959  SCIP_Real* sortkeysC1;
2960  SCIP_Real* sortkeysC2;
2961  SCIP_Real* sortkeysR;
2962  int* nC1varsingubcons;
2963  int var;
2964  int gubconsidx;
2965  int varidx;
2966  int ngubconss;
2967  int ngubconsGOC1;
2968  int targetvar;
2969 #ifndef NDEBUG
2970  int nvarsprocessed = 0;
2971 #endif
2972  int i;
2973  int j;
2974 
2975 #if GUBSPLITGNC1GUBS
2976  SCIP_Bool gubconswithF;
2977  int origngubconss;
2978  origngubconss = gubset->ngubconss;
2979 #endif
2980 
2981  assert(scip != NULL);
2982  assert(gubset != NULL);
2983  assert(solvals != NULL);
2984  assert(weights != NULL);
2985  assert(varsC1 != NULL);
2986  assert(varsC2 != NULL);
2987  assert(varsF != NULL);
2988  assert(varsR != NULL);
2989  assert(nvarsC1 > 0);
2990  assert(nvarsC2 >= 0);
2991  assert(nvarsF >= 0);
2992  assert(nvarsR >= 0);
2993  assert(gubconsGC1 != NULL);
2994  assert(gubconsGC2 != NULL);
2995  assert(gubconsGFC1 != NULL);
2996  assert(gubconsGR != NULL);
2997  assert(ngubconsGC1 != NULL);
2998  assert(ngubconsGC2 != NULL);
2999  assert(ngubconsGFC1 != NULL);
3000  assert(ngubconsGR != NULL);
3001  assert(maxgubvarssize != NULL);
3002 
3003  ngubconss = gubset->ngubconss;
3004  ngubconsGOC1 = 0;
3005 
3006  /* GUBs are categorized into different types according to the variables in volved
3007  * - GOC1: involves variables in C1 only -- no C2, R, F
3008  * - GNC1: involves variables in C1 and F (and R) -- no C2
3009  * - GF: involves variables in F (and R) only -- no C1, C2
3010  * - GC2: involves variables in C2 only -- no C1, R, F
3011  * - GR: involves variables in R only -- no C1, C2, F
3012  * which requires splitting GUBs in case they include variable in F and R.
3013  *
3014  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3015  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3016  * - second ordering level is
3017  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3018  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3019  * GR: non-increasing max{ a_k : k in GR_j}
3020  *
3021  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3022  * - GC1: GUBs of category GOC1 and GNC1
3023  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3024  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3025  */
3026 
3027  /* allocates temporary memory */
3028  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3029  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3030  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3031 
3032  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3033  * - F: non-increasing x*_j and non-increasing a_j in case of equality
3034  * - C2: non-increasing a_j
3035  * - R: non-increasing a_j
3036  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3037  */
3038 
3039  /* gets sorting key for variables in C1 corresponding to the following ordering
3040  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3041  */
3042  for( j = 0; j < nvarsC1; j++ )
3043  {
3044  /* gets sortkeys */
3045  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3046 
3047  /* update status of variable in its gub constraint */
3048  gubconsidx = gubset->gubconssidx[varsC1[j]];
3049  varidx = gubset->gubvarsidx[varsC1[j]];
3050  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3051  }
3052 
3053  /* gets sorting key for variables in F corresponding to the following ordering
3054  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3055  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3056  * and updates status of each variable in F in GUB set data structure
3057  */
3058  for( j = 0; j < nvarsF; j++ )
3059  {
3060  /* update status of variable in its gub constraint */
3061  gubconsidx = gubset->gubconssidx[varsF[j]];
3062  varidx = gubset->gubvarsidx[varsF[j]];
3063  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3064  }
3065 
3066  /* gets sorting key for variables in C2 corresponding to the following ordering
3067  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3068  * and updates status of each variable in F in GUB set data structure
3069  */
3070  for( j = 0; j < nvarsC2; j++ )
3071  {
3072  /* gets sortkeys */
3073  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3074 
3075  /* update status of variable in its gub constraint */
3076  gubconsidx = gubset->gubconssidx[varsC2[j]];
3077  varidx = gubset->gubvarsidx[varsC2[j]];
3078  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3079  }
3080 
3081  /* gets sorting key for variables in R corresponding to the following ordering
3082  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3083  * and updates status of each variable in F in GUB set data structure
3084  */
3085  for( j = 0; j < nvarsR; j++ )
3086  {
3087  /* gets sortkeys */
3088  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3089 
3090  /* update status of variable in its gub constraint */
3091  gubconsidx = gubset->gubconssidx[varsR[j]];
3092  varidx = gubset->gubvarsidx[varsR[j]];
3093  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3094  }
3095 
3096  /* sorts C1, F, C2 and R */
3097  assert(nvarsC1 > 0);
3098  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3099 
3100  if( nvarsC2 > 0 )
3101  {
3102  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3103  }
3104  if( nvarsR > 0)
3105  {
3106  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3107  }
3108 
3109  /* frees temporary memory */
3110  SCIPfreeBufferArray(scip, &sortkeysR);
3111  SCIPfreeBufferArray(scip, &sortkeysC2);
3112  SCIPfreeBufferArray(scip, &sortkeysC1);
3113 
3114  /* allocate and initialize temporary memory for sorting GUB constraints */
3115  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3116  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3117  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3118  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3119  for( i = 0; i < ngubconss; i++)
3120  {
3121  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3122  sortkeypairsGFC1[i]->key1 = 0.0;
3123  sortkeypairsGFC1[i]->key2 = 0.0;
3124  }
3125  *ngubconsGC1 = 0;
3126  *ngubconsGC2 = 0;
3127  *ngubconsGFC1 = 0;
3128  *ngubconsGR = 0;
3129  *ngubconscapexceed = 0;
3130  *maxgubvarssize = 0;
3131 
3132 #ifndef NDEBUG
3133  for( i = 0; i < gubset->ngubconss; i++ )
3134  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3135 #endif
3136 
3137  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3138  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3139  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3140  * non-increasing number of variables in F, and
3141  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3142  */
3143  for( i = 0; i < nvarsC1; i++ )
3144  {
3145  int nvarsC1capexceed;
3146 
3147  nvarsC1capexceed = 0;
3148 
3149  var = varsC1[i];
3150  gubconsidx = gubset->gubconssidx[var];
3151  varidx = gubset->gubvarsidx[var];
3152 
3153  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3154  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3155 
3156  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3157  * note that variables in C1 are already sorted by non-decreasing weigth
3158  */
3159  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3160  GUBsetSwapVars(scip, gubset, var, targetvar);
3161  nC1varsingubcons[gubconsidx]++;
3162 
3163  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3164  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3165  {
3166  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3167  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3168  continue;
3169  }
3170 
3171  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3172  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3173  */
3174 #if GUBSPLITGNC1GUBS
3175  gubconswithF = FALSE;
3176 #endif
3177  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3178  {
3179  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3180 
3181  /* C1-variable: update number of C1/capacity exceeding variables */
3182  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3183  {
3184  nvarsC1capexceed++;
3185 #ifndef NDEBUG
3186  nvarsprocessed++;
3187 #endif
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 #ifndef NDEBUG
3302  nvarsprocessed++;
3303 #endif
3304  }
3305 
3306  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3307  * non-increasing number of variables in F, and
3308  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3309  */
3310  for( i = 0; i < nvarsF; i++ )
3311  {
3312  var = varsF[i];
3313  gubconsidx = gubset->gubconssidx[var];
3314  varidx = gubset->gubvarsidx[var];
3315 
3316  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3317  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3318 
3319 #ifndef NDEBUG
3320  nvarsprocessed++;
3321 #endif
3322 
3323  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3324  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3325  {
3326  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3327  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3328  continue;
3329  }
3330 
3331  /* set status of GF GUB */
3332  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3333 
3334  /* update sorting key of corresponding GFC1 GUB */
3335  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3336  {
3337  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3338  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3339 
3340  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3341  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3342  {
3343  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3344 
3345  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3346  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3347  }
3348  }
3349 
3350  /* update set of GFC1 GUBs */
3351  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3352  (*ngubconsGFC1)++;
3353 
3354  /* update maximum size of all GUB constraints */
3355  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3356  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3357  }
3358 
3359  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3360  * correctly
3361  */
3362  for( i = 0; i < nvarsR; i++ )
3363  {
3364  var = varsR[i];
3365  gubconsidx = gubset->gubconssidx[var];
3366  varidx = gubset->gubvarsidx[var];
3367 
3368  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3369  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3370 
3371 #ifndef NDEBUG
3372  nvarsprocessed++;
3373 #endif
3374 
3375  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3376  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3377  {
3378  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3379  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3380  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3381  continue;
3382  }
3383 
3384  /* set status of GR GUB */
3385  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3386 
3387  /* update set of GR GUBs */
3388  gubconsGR[*ngubconsGR] = gubconsidx;
3389  (*ngubconsGR)++;
3390 
3391  /* update maximum size of all GUB constraints */
3392  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3393  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3394  }
3395  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3396 
3397  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3398  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3399  assert(*ngubconscapexceed >= 0);
3400 #ifndef NDEBUG
3401  {
3402  int check;
3403 
3404  check = 0;
3405 
3406  /* remaining not handled GUBs should only contain capacity exceeding variables */
3407  for( i = 0; i < ngubconss; i++ )
3408  {
3409  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3410  check++;
3411  }
3412  assert(check == *ngubconscapexceed);
3413  }
3414 #endif
3415 
3416  /* sort GFCI GUBs according to computed sorting keys */
3417  if( (*ngubconsGFC1) > 0 )
3418  {
3419  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3420  }
3421 
3422  /* free temporary memory */
3423 #if GUBSPLITGNC1GUBS
3424  ngubconss = origngubconss;
3425 #endif
3426  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3427  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3428  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3429 
3430  return SCIP_OKAY;
3431 }
3432 
3433 /** enlarges minweight table to at least the given length */
3434 static
3436  SCIP* scip, /**< SCIP data structure */
3437  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3438  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3439  int* minweightssize, /**< pointer to current size of minweights table */
3440  int newlen /**< new length of minweights table */
3441  )
3442 {
3443  int j;
3444 
3445  assert(minweightsptr != NULL);
3446  assert(*minweightsptr != NULL);
3447  assert(minweightslen != NULL);
3448  assert(*minweightslen >= 0);
3449  assert(minweightssize != NULL);
3450  assert(*minweightssize >= 0);
3451 
3452  if( newlen > *minweightssize )
3453  {
3454  int newsize;
3455 
3456  /* reallocate table memory */
3457  newsize = SCIPcalcMemGrowSize(scip, newlen);
3458  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3459  *minweightssize = newsize;
3460  }
3461  assert(newlen <= *minweightssize);
3462 
3463  /* initialize new elements */
3464  for( j = *minweightslen; j < newlen; ++j )
3465  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3466  *minweightslen = newlen;
3467 
3468  return SCIP_OKAY;
3469 }
3470 
3471 /** lifts given inequality
3472  * sum_{j in M_1} x_j <= alpha_0
3473  * valid for
3474  * 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 }
3475  * to a valid inequality
3476  * 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
3477  * <= alpha_0 + sum_{j in M_2} alpha_j
3478  * for
3479  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3480  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3481  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3482  * extended weight inequalities.
3483  */
3484 static
3486  SCIP* scip, /**< SCIP data structure */
3487  SCIP_VAR** vars, /**< variables in knapsack constraint */
3488  int nvars, /**< number of variables in knapsack constraint */
3489  int ntightened, /**< number of variables with tightened upper bound */
3490  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3491  SCIP_Longint capacity, /**< capacity of knapsack */
3492  SCIP_Real* solvals, /**< solution values of all problem variables */
3493  int* varsM1, /**< variables in M_1 */
3494  int* varsM2, /**< variables in M_2 */
3495  int* varsF, /**< variables in F */
3496  int* varsR, /**< variables in R */
3497  int nvarsM1, /**< number of variables in M_1 */
3498  int nvarsM2, /**< number of variables in M_2 */
3499  int nvarsF, /**< number of variables in F */
3500  int nvarsR, /**< number of variables in R */
3501  int alpha0, /**< rights hand side of given valid inequality */
3502  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3503  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3504  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3505  )
3506 {
3507  SCIP_Longint* minweights;
3508  SCIP_Real* sortkeys;
3509  SCIP_Longint fixedonesweight;
3510  int minweightssize;
3511  int minweightslen;
3512  int j;
3513  int w;
3514 
3515  assert(scip != NULL);
3516  assert(vars != NULL);
3517  assert(nvars >= 0);
3518  assert(weights != NULL);
3519  assert(capacity >= 0);
3520  assert(solvals != NULL);
3521  assert(varsM1 != NULL);
3522  assert(varsM2 != NULL);
3523  assert(varsF != NULL);
3524  assert(varsR != NULL);
3525  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3526  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3527  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3528  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3529  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3530  assert(alpha0 >= 0);
3531  assert(liftcoefs != NULL);
3532  assert(cutact != NULL);
3533  assert(liftrhs != NULL);
3534 
3535  /* allocates temporary memory */
3536  minweightssize = nvarsM1 + 1;
3537  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3538  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3539 
3540  /* initializes data structures */
3541  BMSclearMemoryArray(liftcoefs, nvars);
3542  *cutact = 0.0;
3543 
3544  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3545  * and calculates activity of the current valid inequality
3546  */
3547  for( j = 0; j < nvarsM1; j++ )
3548  {
3549  assert(liftcoefs[varsM1[j]] == 0);
3550  liftcoefs[varsM1[j]] = 1;
3551  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3552  (*cutact) += solvals[varsM1[j]];
3553  }
3554 
3555  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3556 
3557  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3558  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3559  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3560  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3561  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3562  */
3563  minweights[0] = 0;
3564  for( w = 1; w <= nvarsM1; w++ )
3565  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3566  minweightslen = nvarsM1 + 1;
3567 
3568  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3569  fixedonesweight = 0;
3570  for( j = 0; j < nvarsM2; j++ )
3571  fixedonesweight += weights[varsM2[j]];
3572  assert(fixedonesweight >= 0);
3573 
3574  /* initializes right hand side of lifted valid inequality */
3575  *liftrhs = alpha0;
3576 
3577  /* sequentially up-lifts all variables in F: */
3578  for( j = 0; j < nvarsF; j++ )
3579  {
3580  SCIP_Longint weight;
3581  int liftvar;
3582  int liftcoef;
3583  int z;
3584 
3585  liftvar = varsF[j];
3586  weight = weights[liftvar];
3587  assert(liftvar >= 0 && liftvar < nvars);
3588  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3589  assert(weight > 0);
3590 
3591  /* knapsack problem is infeasible:
3592  * sets z = 0
3593  */
3594  if( capacity - fixedonesweight - weight < 0 )
3595  {
3596  z = 0;
3597  }
3598  /* knapsack problem is feasible:
3599  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3600  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3601  */
3602  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3603  {
3604  z = *liftrhs;
3605  }
3606  /* knapsack problem is feasible:
3607  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3608  */
3609  else
3610  {
3611  int left;
3612  int right;
3613  int middle;
3614 
3615  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3616  left = 0;
3617  right = (*liftrhs) + 1;
3618  while( left < right - 1 )
3619  {
3620  middle = (left + right) / 2;
3621  assert(0 <= middle && middle < minweightslen);
3622  if( minweights[middle] <= capacity - fixedonesweight - weight )
3623  left = middle;
3624  else
3625  right = middle;
3626  }
3627  assert(left == right - 1);
3628  assert(0 <= left && left < minweightslen);
3629  assert(minweights[left] <= capacity - fixedonesweight - weight );
3630  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3631 
3632  /* now z = left */
3633  z = left;
3634  assert(z <= *liftrhs);
3635  }
3636 
3637  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3638  liftcoef = (*liftrhs) - z;
3639  liftcoefs[liftvar] = liftcoef;
3640  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3641 
3642  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3643  if( liftcoef == 0 )
3644  continue;
3645 
3646  /* updates activity of current valid inequality */
3647  (*cutact) += liftcoef * solvals[liftvar];
3648 
3649  /* enlarges current minweight table:
3650  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3651  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3652  * and sets minweights_i[w] = infinity for
3653  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3654  */
3655  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3656 
3657  /* updates minweight table: minweight_i+1[w] =
3658  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3659  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3660  */
3661  for( w = minweightslen - 1; w >= 0; w-- )
3662  {
3663  SCIP_Longint min;
3664  if( w < liftcoef )
3665  {
3666  min = MIN(minweights[w], weight);
3667  minweights[w] = min;
3668  }
3669  else
3670  {
3671  assert(w >= liftcoef);
3672  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3673  minweights[w] = min;
3674  }
3675  }
3676  }
3677  assert(minweights[0] == 0);
3678 
3679  /* sequentially down-lifts all variables in M_2: */
3680  for( j = 0; j < nvarsM2; j++ )
3681  {
3682  SCIP_Longint weight;
3683  int liftvar;
3684  int liftcoef;
3685  int left;
3686  int right;
3687  int middle;
3688  int z;
3689 
3690  liftvar = varsM2[j];
3691  weight = weights[liftvar];
3692  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3693  assert(liftvar >= 0 && liftvar < nvars);
3694  assert(weight > 0);
3695 
3696  /* uses binary search to find
3697  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3698  */
3699  left = 0;
3700  right = minweightslen;
3701  while( left < right - 1 )
3702  {
3703  middle = (left + right) / 2;
3704  assert(0 <= middle && middle < minweightslen);
3705  if( minweights[middle] <= capacity - fixedonesweight + weight )
3706  left = middle;
3707  else
3708  right = middle;
3709  }
3710  assert(left == right - 1);
3711  assert(0 <= left && left < minweightslen);
3712  assert(minweights[left] <= capacity - fixedonesweight + weight );
3713  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3714 
3715  /* now z = left */
3716  z = left;
3717  assert(z >= *liftrhs);
3718 
3719  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3720  liftcoef = z - (*liftrhs);
3721  liftcoefs[liftvar] = liftcoef;
3722  assert(liftcoef >= 0);
3723 
3724  /* updates sum of weights of variables fixed to one */
3725  fixedonesweight -= weight;
3726 
3727  /* updates right-hand side of current valid inequality */
3728  (*liftrhs) += liftcoef;
3729  assert(*liftrhs >= alpha0);
3730 
3731  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3732  if( liftcoef == 0 )
3733  continue;
3734 
3735  /* updates activity of current valid inequality */
3736  (*cutact) += liftcoef * solvals[liftvar];
3737 
3738  /* enlarges current minweight table:
3739  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3740  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3741  * and sets minweights_i[w] = infinity for
3742  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3743  */
3744  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3745 
3746  /* updates minweight table: minweight_i+1[w] =
3747  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3748  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3749  */
3750  for( w = minweightslen - 1; w >= 0; w-- )
3751  {
3752  SCIP_Longint min;
3753  if( w < liftcoef )
3754  {
3755  min = MIN(minweights[w], weight);
3756  minweights[w] = min;
3757  }
3758  else
3759  {
3760  assert(w >= liftcoef);
3761  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3762  minweights[w] = min;
3763  }
3764  }
3765  }
3766  assert(fixedonesweight == 0);
3767  assert(*liftrhs >= alpha0);
3768 
3769  /* sequentially up-lifts all variables in R: */
3770  for( j = 0; j < nvarsR; j++ )
3771  {
3772  SCIP_Longint weight;
3773  int liftvar;
3774  int liftcoef;
3775  int z;
3776 
3777  liftvar = varsR[j];
3778  weight = weights[liftvar];
3779  assert(liftvar >= 0 && liftvar < nvars);
3780  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3781  assert(weight > 0);
3782  assert(capacity - weight >= 0);
3783  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3784 
3785  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3786  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3787  */
3788  if( minweights[*liftrhs] <= capacity - weight )
3789  {
3790  z = *liftrhs;
3791  }
3792  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3793  */
3794  else
3795  {
3796  int left;
3797  int right;
3798  int middle;
3799 
3800  left = 0;
3801  right = (*liftrhs) + 1;
3802  while( left < right - 1)
3803  {
3804  middle = (left + right) / 2;
3805  assert(0 <= middle && middle < minweightslen);
3806  if( minweights[middle] <= capacity - weight )
3807  left = middle;
3808  else
3809  right = middle;
3810  }
3811  assert(left == right - 1);
3812  assert(0 <= left && left < minweightslen);
3813  assert(minweights[left] <= capacity - weight );
3814  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3815 
3816  /* now z = left */
3817  z = left;
3818  assert(z <= *liftrhs);
3819  }
3820 
3821  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3822  liftcoef = (*liftrhs) - z;
3823  liftcoefs[liftvar] = liftcoef;
3824  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3825 
3826  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3827  if( liftcoef == 0 )
3828  continue;
3829 
3830  /* updates activity of current valid inequality */
3831  (*cutact) += liftcoef * solvals[liftvar];
3832 
3833  /* updates minweight table: minweight_i+1[w] =
3834  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3835  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3836  */
3837  for( w = *liftrhs; w >= 0; w-- )
3838  {
3839  SCIP_Longint min;
3840  if( w < liftcoef )
3841  {
3842  min = MIN(minweights[w], weight);
3843  minweights[w] = min;
3844  }
3845  else
3846  {
3847  assert(w >= liftcoef);
3848  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3849  minweights[w] = min;
3850  }
3851  }
3852  }
3853 
3854  /* frees temporary memory */
3855  SCIPfreeBufferArray(scip, &sortkeys);
3856  SCIPfreeBufferArray(scip, &minweights);
3857 
3858  return SCIP_OKAY;
3859 }
3860 
3861 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3862 static
3864  SCIP_Longint val1, /**< first value to add */
3865  SCIP_Longint val2 /**< second value to add */
3866  )
3867 {
3868  assert(val1 >= 0);
3869  assert(val2 >= 0);
3870 
3871  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3872  return SCIP_LONGINT_MAX;
3873  else
3874  {
3875  assert(val1 <= SCIP_LONGINT_MAX - val2);
3876  return (val1 + val2);
3877  }
3878 }
3879 
3880 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3881 static
3883  SCIP_Longint* minweights, /**< minweight table to compute */
3884  SCIP_Longint* finished, /**< given finished table */
3885  SCIP_Longint* unfinished, /**< given unfinished table */
3886  int minweightslen /**< length of minweight, finished, and unfinished tables */
3887  )
3888 {
3889  int w1;
3890  int w2;
3891 
3892  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3893  * note that finished and unfished arrays sorted by non-decreasing weight
3894  */
3895 
3896  /* initialize minweight with w2 = 0 */
3897  w2 = 0;
3898  assert(unfinished[w2] == 0);
3899  for( w1 = 0; w1 < minweightslen; w1++ )
3900  minweights[w1] = finished[w1];
3901 
3902  /* consider w2 = 1, ..., minweightslen-1 */
3903  for( w2 = 1; w2 < minweightslen; w2++ )
3904  {
3905  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3906  break;
3907 
3908  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3909  {
3910  SCIP_Longint temp;
3911 
3912  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3913  if( temp <= minweights[w1+w2] )
3914  minweights[w1+w2] = temp;
3915  }
3916  }
3917 }
3918 
3919 /** lifts given inequality
3920  * sum_{j in C_1} x_j <= alpha_0
3921  * valid for
3922  * 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;
3923  * sum_{j in Q_i} x_j <= 1, forall i in I }
3924  * to a valid inequality
3925  * 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
3926  * <= alpha_0 + sum_{j in C_2} alpha_j
3927  * for
3928  * 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 };
3929  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3930  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3931  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3932  */
3933 static
3935  SCIP* scip, /**< SCIP data structure */
3936  SCIP_GUBSET* gubset, /**< GUB set data structure */
3937  SCIP_VAR** vars, /**< variables in knapsack constraint */
3938  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3939  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3940  SCIP_Longint capacity, /**< capacity of knapsack */
3941  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3942  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3943  int* gubconsGC2, /**< GUBs in GC2 */
3944  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3945  int* gubconsGR, /**< GUBs in GR */
3946  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3947  int ngubconsGC2, /**< number of GUBs in GC2 */
3948  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3949  int ngubconsGR, /**< number of GUBs in GR */
3950  int alpha0, /**< rights hand side of given valid inequality */
3951  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3952  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3953  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3954  int maxgubvarssize /**< maximal size of GUB constraints */
3955  )
3956 {
3957  SCIP_Longint* minweights;
3958  SCIP_Longint* finished;
3959  SCIP_Longint* unfinished;
3960  int* gubconsGOC1;
3961  int* gubconsGNC1;
3962  int* liftgubvars;
3963  SCIP_Longint fixedonesweight;
3964  SCIP_Longint weight;
3965  SCIP_Longint weightdiff1;
3966  SCIP_Longint weightdiff2;
3967  SCIP_Longint min;
3968  int minweightssize;
3969  int minweightslen;
3970  int nvars;
3971  int varidx;
3972  int liftgubconsidx;
3973  int liftvar;
3974  int sumliftcoef;
3975  int liftcoef;
3976  int ngubconsGOC1;
3977  int ngubconsGNC1;
3978  int left;
3979  int right;
3980  int middle;
3981  int nliftgubvars;
3982  int tmplen;
3983  int tmpsize;
3984  int j;
3985  int k;
3986  int w;
3987  int z;
3988 #ifndef NDEBUG
3989  int ngubconss;
3990  int nliftgubC1;
3991 
3992  assert(gubset != NULL);
3993  ngubconss = gubset->ngubconss;
3994 #else
3995  assert(gubset != NULL);
3996 #endif
3997 
3998  nvars = gubset->nvars;
3999 
4000  assert(scip != NULL);
4001  assert(vars != NULL);
4002  assert(nvars >= 0);
4003  assert(weights != NULL);
4004  assert(capacity >= 0);
4005  assert(solvals != NULL);
4006  assert(gubconsGC1 != NULL);
4007  assert(gubconsGC2 != NULL);
4008  assert(gubconsGFC1 != NULL);
4009  assert(gubconsGR != NULL);
4010  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4011  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4012  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4013  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4014  assert(alpha0 >= 0);
4015  assert(liftcoefs != NULL);
4016  assert(cutact != NULL);
4017  assert(liftrhs != NULL);
4018 
4019  minweightssize = ngubconsGC1+1;
4020 
4021  /* allocates temporary memory */
4022  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4023  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4024  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4025  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4026  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4027  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4028 
4029  /* initializes data structures */
4030  BMSclearMemoryArray(liftcoefs, nvars);
4031  *cutact = 0.0;
4032 
4033  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4034  * valid inequality
4035  */
4036  ngubconsGOC1 = 0;
4037  ngubconsGNC1 = 0;
4038  for( j = 0; j < ngubconsGC1; j++ )
4039  {
4040  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4041  {
4042  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4043  ngubconsGOC1++;
4044  }
4045  else
4046  {
4047  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4048  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4049  ngubconsGNC1++;
4050  }
4051  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4052  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4053  {
4054  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4055  assert(varidx >= 0 && varidx < nvars);
4056  assert(liftcoefs[varidx] == 0);
4057 
4058  liftcoefs[varidx] = 1;
4059  (*cutact) += solvals[varidx];
4060  }
4061  assert(k >= 1);
4062  }
4063  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4064  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4065 
4066  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4067  * - finished_i[w] =
4068  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4069  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4070  * sum_{j in Q_k} x_j <= 1
4071  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4072  * - unfinished_i[w] =
4073  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4074  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4075  * sum_{j in Q_k} x_j <= 1
4076  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4077  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4078  */
4079 
4080  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4081  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4082  * 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
4083  * comes from the first variable in the GUB
4084  */
4085  assert(ngubconsGOC1 <= ngubconsGC1);
4086  finished[0] = 0;
4087  for( w = 1; w <= ngubconsGOC1; w++ )
4088  {
4089  liftgubconsidx = gubconsGOC1[w-1];
4090 
4091  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4092  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4093 
4094  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4095 
4096  assert(varidx >= 0 && varidx < nvars);
4097  assert(liftcoefs[varidx] == 1);
4098 
4099  min = weights[varidx];
4100  finished[w] = finished[w-1] + min;
4101 
4102 #ifndef NDEBUG
4103  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4104  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4105  {
4106  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4107  assert(varidx >= 0 && varidx < nvars);
4108  assert(liftcoefs[varidx] == 1);
4109  assert(weights[varidx] >= min);
4110  }
4111 #endif
4112  }
4113  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4114  finished[w] = SCIP_LONGINT_MAX;
4115 
4116  /* initialize unfinished table; note that variables in GNC1 GUBs
4117  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4118  * 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
4119  * comes from the first variable in the GUB
4120  */
4121  assert(ngubconsGNC1 <= ngubconsGC1);
4122  unfinished[0] = 0;
4123  for( w = 1; w <= ngubconsGNC1; w++ )
4124  {
4125  liftgubconsidx = gubconsGNC1[w-1];
4126 
4127  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4128  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4129 
4130  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4131 
4132  assert(varidx >= 0 && varidx < nvars);
4133  assert(liftcoefs[varidx] == 1);
4134 
4135  min = weights[varidx];
4136  unfinished[w] = unfinished[w-1] + min;
4137 
4138 #ifndef NDEBUG
4139  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4140  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4141  {
4142  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4143  assert(varidx >= 0 && varidx < nvars);
4144  assert(liftcoefs[varidx] == 1);
4145  assert(weights[varidx] >= min );
4146  }
4147 #endif
4148  }
4149  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4150  unfinished[w] = SCIP_LONGINT_MAX;
4151 
4152  /* initialize minweights table; note that variables in GC1 GUBs
4153  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4154  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4155  * consuming) because is it has to be build using weights from C1 only.
4156  */
4157  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4158  minweights[0] = 0;
4159  for( w = 1; w <= ngubconsGC1; w++ )
4160  {
4161  liftgubconsidx = gubconsGC1[w-1];
4162 
4163  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4164  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4165  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4166 
4167  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4168 
4169  assert(varidx >= 0 && varidx < nvars);
4170  assert(liftcoefs[varidx] == 1);
4171 
4172  min = weights[varidx];
4173  minweights[w] = minweights[w-1] + min;
4174 
4175 #ifndef NDEBUG
4176  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4177  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4178  {
4179  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4180  assert(varidx >= 0 && varidx < nvars);
4181  assert(liftcoefs[varidx] == 1);
4182  assert(weights[varidx] >= min);
4183  }
4184 #endif
4185  }
4186  minweightslen = ngubconsGC1 + 1;
4187 
4188  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4189  fixedonesweight = 0;
4190  for( j = 0; j < ngubconsGC2; j++ )
4191  {
4192  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4193 
4194  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4195  assert(varidx >= 0 && varidx < nvars);
4196  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4197 
4198  fixedonesweight += weights[varidx];
4199  }
4200  assert(fixedonesweight >= 0);
4201 
4202  /* initializes right hand side of lifted valid inequality */
4203  *liftrhs = alpha0;
4204 
4205  /* sequentially up-lifts all variables in GFC1 GUBs */
4206  for( j = 0; j < ngubconsGFC1; j++ )
4207  {
4208  liftgubconsidx = gubconsGFC1[j];
4209  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4210 
4211  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4212  * compute minweight table via updated unfinished table and aleady upto date finished table;
4213  */
4214  k = 0;
4215  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4216  {
4217  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4218  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4219  assert(ngubconsGNC1 > 0);
4220 
4221  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4222  * are considered for the lifting, i.e., not capacity exceeding
4223  */
4224  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4225  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4226  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4227  assert(k >= 1);
4228 
4229  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4230  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4231  */
4232  weight = weights[liftgubvars[0]];
4233 
4234  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4235  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4236  for( w = ngubconsGNC1-1; w >= 1; w-- )
4237  {
4238  weightdiff1 = weightdiff2;
4239  weightdiff2 = unfinished[w] - weight;
4240 
4241  if( unfinished[w] < weightdiff1 )
4242  unfinished[w] = weightdiff1;
4243  else
4244  break;
4245  }
4246  ngubconsGNC1--;
4247 
4248  /* computes minweights table by combining unfished and fished tables */
4249  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4250  assert(minweights[0] == 0);
4251  }
4252  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4253  * are therefore not in the unfinished table
4254  */
4255  else
4256  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4257 
4258 #ifndef NDEBUG
4259  nliftgubC1 = k;
4260 #endif
4261  nliftgubvars = k;
4262  sumliftcoef = 0;
4263 
4264  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4265  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4266  {
4267  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4268  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4269  {
4270  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4271  weight = weights[liftvar];
4272  assert(weight > 0);
4273  assert(liftvar >= 0 && liftvar < nvars);
4274  assert(capacity - weight >= 0);
4275 
4276  /* put variable into array of variables in GUB that are considered for the lifting,
4277  * i.e., not capacity exceeding
4278  */
4279  liftgubvars[nliftgubvars] = liftvar;
4280  nliftgubvars++;
4281 
4282  /* knapsack problem is infeasible:
4283  * sets z = 0
4284  */
4285  if( capacity - fixedonesweight - weight < 0 )
4286  {
4287  z = 0;
4288  }
4289  /* knapsack problem is feasible:
4290  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4291  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4292  */
4293  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4294  {
4295  z = *liftrhs;
4296  }
4297  /* knapsack problem is feasible:
4298  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4299  */
4300  else
4301  {
4302  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4303  left = 0;
4304  right = (*liftrhs) + 1;
4305  while( left < right - 1 )
4306  {
4307  middle = (left + right) / 2;
4308  assert(0 <= middle && middle < minweightslen);
4309  if( minweights[middle] <= capacity - fixedonesweight - weight )
4310  left = middle;
4311  else
4312  right = middle;
4313  }
4314  assert(left == right - 1);
4315  assert(0 <= left && left < minweightslen);
4316  assert(minweights[left] <= capacity - fixedonesweight - weight);
4317  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4318 
4319  /* now z = left */
4320  z = left;
4321  assert(z <= *liftrhs);
4322  }
4323 
4324  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4325  liftcoef = (*liftrhs) - z;
4326  liftcoefs[liftvar] = liftcoef;
4327  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4328 
4329  /* updates activity of current valid inequality */
4330  (*cutact) += liftcoef * solvals[liftvar];
4331 
4332  /* updates sum of all lifting coefficients in GUB */
4333  sumliftcoef += liftcoefs[liftvar];
4334  }
4335  else
4336  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4337  }
4338  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4339  assert(nliftgubvars > nliftgubC1);
4340 
4341  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4342  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4343  * not needed for GF GUBs
4344  */
4345  if( sumliftcoef == 0 )
4346  {
4347  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4348  {
4349  weight = weights[liftgubvars[0]];
4350  /* update finished table and minweights table by applying special case of
4351  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4352  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4353  */
4354  for( w = minweightslen-1; w >= 1; w-- )
4355  {
4356  SCIP_Longint tmpval;
4357 
4358  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4359  finished[w] = MIN(finished[w], tmpval);
4360 
4361  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4362  minweights[w] = MIN(minweights[w], tmpval);
4363  }
4364  }
4365  else
4366  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4367 
4368  continue;
4369  }
4370 
4371  /* enlarges current minweights tables(finished, unfinished, minweights):
4372  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4373  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4374  * and sets minweights_i[w] = infinity for
4375  * 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
4376  */
4377  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4378  tmpsize = minweightssize;
4379  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4380  tmplen = minweightslen;
4381  tmpsize = minweightssize;
4382  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4383  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4384 
4385  /* update finished table and minweight table;
4386  * note that instead of computing minweight table from updated finished and updated unfinished table again
4387  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4388  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4389  * not needed because only finished table changed at this point and the change was "adding" one weight)
4390  *
4391  * update formular for minweight table is: minweight_i+1[w] =
4392  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4393  * formular for finished table has the same pattern.
4394  */
4395  for( w = minweightslen-1; w >= 0; w-- )
4396  {
4397  SCIP_Longint minminweight;
4398  SCIP_Longint minfinished;
4399 
4400  for( k = 0; k < nliftgubvars; k++ )
4401  {
4402  liftcoef = liftcoefs[liftgubvars[k]];
4403  weight = weights[liftgubvars[k]];
4404 
4405  if( w < liftcoef )
4406  {
4407  minfinished = MIN(finished[w], weight);
4408  minminweight = MIN(minweights[w], weight);
4409 
4410  finished[w] = minfinished;
4411  minweights[w] = minminweight;
4412  }
4413  else
4414  {
4415  SCIP_Longint tmpval;
4416 
4417  assert(w >= liftcoef);
4418 
4419  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4420  minfinished = MIN(finished[w], tmpval);
4421 
4422  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4423  minminweight = MIN(minweights[w], tmpval);
4424 
4425  finished[w] = minfinished;
4426  minweights[w] = minminweight;
4427  }
4428  }
4429  }
4430  assert(minweights[0] == 0);
4431  }
4432  assert(ngubconsGNC1 == 0);
4433 
4434  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4435  * therefore, only work with minweight table from here on
4436  */
4437 
4438  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4439  for( j = 0; j < ngubconsGC2; j++ )
4440  {
4441  liftgubconsidx = gubconsGC2[j];
4442 
4443  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4444  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4445  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4446  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4447 
4448  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4449  weight = weights[liftvar];
4450 
4451  assert(liftvar >= 0 && liftvar < nvars);
4452  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4453  assert(weight > 0);
4454 
4455  /* uses binary search to find
4456  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4457  */
4458  left = 0;
4459  right = minweightslen;
4460  while( left < right - 1 )
4461  {
4462  middle = (left + right) / 2;
4463  assert(0 <= middle && middle < minweightslen);
4464  if( minweights[middle] <= capacity - fixedonesweight + weight )
4465  left = middle;
4466  else
4467  right = middle;
4468  }
4469  assert(left == right - 1);
4470  assert(0 <= left && left < minweightslen);
4471  assert(minweights[left] <= capacity - fixedonesweight + weight);
4472  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4473 
4474  /* now z = left */
4475  z = left;
4476  assert(z >= *liftrhs);
4477 
4478  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4479  liftcoef = z - (*liftrhs);
4480  liftcoefs[liftvar] = liftcoef;
4481  assert(liftcoef >= 0);
4482 
4483  /* updates sum of weights of variables fixed to one */
4484  fixedonesweight -= weight;
4485 
4486  /* updates right-hand side of current valid inequality */
4487  (*liftrhs) += liftcoef;
4488  assert(*liftrhs >= alpha0);
4489 
4490  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4491  if( liftcoef == 0 )
4492  continue;
4493 
4494  /* updates activity of current valid inequality */
4495  (*cutact) += liftcoef * solvals[liftvar];
4496 
4497  /* enlarges current minweight table:
4498  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4499  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4500  * and sets minweights_i[w] = infinity for
4501  * 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
4502  */
4503  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4504 
4505  /* updates minweight table: minweight_i+1[w] =
4506  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4507  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4508  */
4509  for( w = minweightslen - 1; w >= 0; w-- )
4510  {
4511  if( w < liftcoef )
4512  {
4513  min = MIN(minweights[w], weight);
4514  minweights[w] = min;
4515  }
4516  else
4517  {
4518  SCIP_Longint tmpval;
4519 
4520  assert(w >= liftcoef);
4521 
4522  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4523  min = MIN(minweights[w], tmpval);
4524  minweights[w] = min;
4525  }
4526  }
4527  }
4528  assert(fixedonesweight == 0);
4529  assert(*liftrhs >= alpha0);
4530 
4531  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4532  for( j = 0; j < ngubconsGR; j++ )
4533  {
4534  liftgubconsidx = gubconsGR[j];
4535 
4536  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4537  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4538 
4539  sumliftcoef = 0;
4540  nliftgubvars = 0;
4541  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4542  {
4543  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4544  {
4545  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4546  weight = weights[liftvar];
4547  assert(weight > 0);
4548  assert(liftvar >= 0 && liftvar < nvars);
4549  assert(capacity - weight >= 0);
4550  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4551 
4552  /* put variable into array of variables in GUB that are considered for the lifting,
4553  * i.e., not capacity exceeding
4554  */
4555  liftgubvars[nliftgubvars] = liftvar;
4556  nliftgubvars++;
4557 
4558  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4559  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4560  */
4561  if( minweights[*liftrhs] <= capacity - weight )
4562  {
4563  z = *liftrhs;
4564  }
4565  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4566  */
4567  else
4568  {
4569  left = 0;
4570  right = (*liftrhs) + 1;
4571  while( left < right - 1 )
4572  {
4573  middle = (left + right) / 2;
4574  assert(0 <= middle && middle < minweightslen);
4575  if( minweights[middle] <= capacity - weight )
4576  left = middle;
4577  else
4578  right = middle;
4579  }
4580  assert(left == right - 1);
4581  assert(0 <= left && left < minweightslen);
4582  assert(minweights[left] <= capacity - weight);
4583  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4584 
4585  /* now z = left */
4586  z = left;
4587  assert(z <= *liftrhs);
4588  }
4589  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4590  liftcoef = (*liftrhs) - z;
4591  liftcoefs[liftvar] = liftcoef;
4592  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4593 
4594  /* updates activity of current valid inequality */
4595  (*cutact) += liftcoef * solvals[liftvar];
4596 
4597  /* updates sum of all lifting coefficients in GUB */
4598  sumliftcoef += liftcoefs[liftvar];
4599  }
4600  else
4601  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4602  }
4603  assert(nliftgubvars >= 1); /* at least one variable is in R */
4604 
4605  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4606  if( sumliftcoef == 0 )
4607  continue;
4608 
4609  /* updates minweight table: minweight_i+1[w] =
4610  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4611  */
4612  for( w = *liftrhs; w >= 0; w-- )
4613  {
4614  for( k = 0; k < nliftgubvars; k++ )
4615  {
4616  liftcoef = liftcoefs[liftgubvars[k]];
4617  weight = weights[liftgubvars[k]];
4618 
4619  if( w < liftcoef )
4620  {
4621  min = MIN(minweights[w], weight);
4622  minweights[w] = min;
4623  }
4624  else
4625  {
4626  SCIP_Longint tmpval;
4627 
4628  assert(w >= liftcoef);
4629 
4630  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4631  min = MIN(minweights[w], tmpval);
4632  minweights[w] = min;
4633  }
4634  }
4635  }
4636  assert(minweights[0] == 0);
4637  }
4638 
4639  /* frees temporary memory */
4640  SCIPfreeBufferArray(scip, &minweights);
4641  SCIPfreeBufferArray(scip, &finished);
4642  SCIPfreeBufferArray(scip, &unfinished);
4643  SCIPfreeBufferArray(scip, &liftgubvars);
4644  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4645  SCIPfreeBufferArray(scip, &gubconsGNC1);
4646 
4647  return SCIP_OKAY;
4648 }
4649 
4650 /** lifts given minimal cover inequality
4651  * \f[
4652  * \sum_{j \in C} x_j \leq |C| - 1
4653  * \f]
4654  * valid for
4655  * \f[
4656  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4657  * \f]
4658  * to a valid inequality
4659  * \f[
4660  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4661  * \f]
4662  * for
4663  * \f[
4664  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4665  * \f]
4666  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4667  */
4668 static
4670  SCIP* scip, /**< SCIP data structure */
4671  SCIP_VAR** vars, /**< variables in knapsack constraint */
4672  int nvars, /**< number of variables in knapsack constraint */
4673  int ntightened, /**< number of variables with tightened upper bound */
4674  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4675  SCIP_Longint capacity, /**< capacity of knapsack */
4676  SCIP_Real* solvals, /**< solution values of all problem variables */
4677  int* covervars, /**< cover variables */
4678  int* noncovervars, /**< noncover variables */
4679  int ncovervars, /**< number of cover variables */
4680  int nnoncovervars, /**< number of noncover variables */
4681  SCIP_Longint coverweight, /**< weight of cover */
4682  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4683  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4684  )
4685 {
4686  SCIP_Longint* maxweightsums;
4687  SCIP_Longint* intervalends;
4688  SCIP_Longint* rhos;
4689  SCIP_Real* sortkeys;
4690  SCIP_Longint lambda;
4691  int j;
4692  int h;
4693 
4694  assert(scip != NULL);
4695  assert(vars != NULL);
4696  assert(nvars >= 0);
4697  assert(weights != NULL);
4698  assert(capacity >= 0);
4699  assert(solvals != NULL);
4700  assert(covervars != NULL);
4701  assert(noncovervars != NULL);
4702  assert(ncovervars > 0 && ncovervars <= nvars);
4703  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4704  assert(ncovervars + nnoncovervars == nvars - ntightened);
4705  assert(liftcoefs != NULL);
4706  assert(cutact != NULL);
4707 
4708  /* allocates temporary memory */
4709  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4710  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4711  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4712  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4713 
4714  /* initializes data structures */
4715  BMSclearMemoryArray(liftcoefs, nvars);
4716  *cutact = 0.0;
4717 
4718  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4719  * and calculates activity of current valid inequality
4720  */
4721  for( j = 0; j < ncovervars; j++ )
4722  {
4723  assert(liftcoefs[covervars[j]] == 0.0);
4724  liftcoefs[covervars[j]] = 1.0;
4725  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4726  (*cutact) += solvals[covervars[j]];
4727  }
4728  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4729 
4730  /* calculates weight excess of cover C */
4731  lambda = coverweight - capacity;
4732  assert(lambda > 0);
4733 
4734  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4735  maxweightsums[0] = 0;
4736  for( h = 1; h <= ncovervars; h++ )
4737  {
4738  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4739  intervalends[h-1] = maxweightsums[h] - lambda;
4740  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4741  }
4742 
4743  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4744  for( j = 0; j < nnoncovervars; j++ )
4745  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4746  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4747 
4748  /* calculates lifting coefficient for all variables in N\C */
4749  h = 0;
4750  for( j = 0; j < nnoncovervars; j++ )
4751  {
4752  int liftvar;
4753  SCIP_Longint weight;
4754  SCIP_Real liftcoef;
4755 
4756  liftvar = noncovervars[j];
4757  weight = weights[liftvar];
4758 
4759  while( intervalends[h] < weight )
4760  h++;
4761 
4762  if( h == 0 )
4763  liftcoef = h;
4764  else
4765  {
4766  if( weight <= intervalends[h-1] + rhos[h] )
4767  {
4768  SCIP_Real tmp1;
4769  SCIP_Real tmp2;
4770  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4771  tmp2 = (SCIP_Real) rhos[1];
4772  liftcoef = h - ( tmp1 / tmp2 );
4773  }
4774  else
4775  liftcoef = h;
4776  }
4777 
4778  /* sets lifting coefficient */
4779  assert(liftcoefs[liftvar] == 0.0);
4780  liftcoefs[liftvar] = liftcoef;
4781 
4782  /* updates activity of current valid inequality */
4783  (*cutact) += liftcoef * solvals[liftvar];
4784  }
4785 
4786  /* frees temporary memory */
4787  SCIPfreeBufferArray(scip, &rhos);
4788  SCIPfreeBufferArray(scip, &intervalends);
4789  SCIPfreeBufferArray(scip, &maxweightsums);
4790  SCIPfreeBufferArray(scip, &sortkeys);
4791 
4792  return SCIP_OKAY;
4793 }
4794 
4795 
4796 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4797  * given knapsack problem
4798 */
4799 static
4801  SCIP* scip, /**< SCIP data structure */
4802  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4803  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4804  SCIP_VAR** vars, /**< variables in knapsack constraint */
4805  int nvars, /**< number of variables in knapsack constraint */
4806  int ntightened, /**< number of variables with tightened upper bound */
4807  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4808  SCIP_Longint capacity, /**< capacity of knapsack */
4809  SCIP_Real* solvals, /**< solution values of all problem variables */
4810  int* mincovervars, /**< mincover variables */
4811  int* nonmincovervars, /**< nonmincover variables */
4812  int nmincovervars, /**< number of mincover variables */
4813  int nnonmincovervars, /**< number of nonmincover variables */
4814  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4815  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4816  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4817  int* ncuts /**< pointer to add up the number of found cuts */
4818  )
4819 {
4820  int* varsC1;
4821  int* varsC2;
4822  int* varsF;
4823  int* varsR;
4824  int nvarsC1;
4825  int nvarsC2;
4826  int nvarsF;
4827  int nvarsR;
4828  SCIP_Real cutact;
4829  int* liftcoefs;
4830  int liftrhs;
4831 
4832  assert( cutoff != NULL );
4833  *cutoff = FALSE;
4834 
4835  /* allocates temporary memory */
4836  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4837  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4838  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4839  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4840  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4841 
4842  /* 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
4843  * as follows
4844  * C_2 = { j in C : x*_j = 1 } and
4845  * C_1 = C\C_2
4846  */
4847  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4848  assert(nvarsC1 + nvarsC2 == nmincovervars);
4849  assert(nmincovervars > 0);
4850  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4851 
4852  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4853  if( nvarsC1 < 2 && nvarsC2 > 0)
4854  {
4855  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4856  assert(nvarsC1 >= 1);
4857  }
4858  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4859 
4860  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4861  * R = { j in N\C : x*_j = 0 } and
4862  * F = (N\C)\F
4863  */
4864  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4865  assert(nvarsF + nvarsR == nnonmincovervars);
4866  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4867 
4868  /* lift cuts without GUB information */
4869  if( gubset == NULL )
4870  {
4871  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4872  * lifting procedure
4873  */
4874  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4875 
4876  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4877  *
4878  * 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 }
4879  *
4880  * 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
4881  *
4882  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4883  *
4884  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4885  * up-lifting for the variables in R according to the second level lifting sequence
4886  */
4887  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4888  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4889  }
4890  /* lift cuts with GUB information */
4891  else
4892  {
4893  int* gubconsGC1;
4894  int* gubconsGC2;
4895  int* gubconsGFC1;
4896  int* gubconsGR;
4897  int ngubconsGC1;
4898  int ngubconsGC2;
4899  int ngubconsGFC1;
4900  int ngubconsGR;
4901  int ngubconss;
4902  int nconstightened;
4903  int maxgubvarssize;
4904 
4905  assert(nvars == gubset->nvars);
4906 
4907  ngubconsGC1 = 0;
4908  ngubconsGC2 = 0;
4909  ngubconsGFC1 = 0;
4910  ngubconsGR = 0;
4911  ngubconss = gubset->ngubconss;
4912  nconstightened = 0;
4913  maxgubvarssize = 0;
4914 
4915  /* allocates temporary memory */
4916  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4917  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4918  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4919  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4920 
4921  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4922  * the GUBs for the sequential GUB wise lifting procedure
4923  */
4924  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4925  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4926  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4927 
4928  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4929  *
4930  * 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,
4931  * sum_{j in Q_i} x_j <= 1, forall i in I }
4932  *
4933  * 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
4934  *
4935  * 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 },
4936  *
4937  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4938  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4939  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4940  */
4941  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4942  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4943  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4944 
4945  /* frees temporary memory */
4946  SCIPfreeBufferArray(scip, &gubconsGR);
4947  SCIPfreeBufferArray(scip, &gubconsGFC1);
4948  SCIPfreeBufferArray(scip, &gubconsGC2);
4949  SCIPfreeBufferArray(scip, &gubconsGC1);
4950  }
4951 
4952  /* checks, if lifting yielded a violated cut */
4953  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4954  {
4955  SCIP_ROW* row;
4956  char name[SCIP_MAXSTRLEN];
4957  int j;
4958 
4959  /* creates LP row */
4960  assert( cons == NULL || sepa == NULL );
4961  if ( cons != NULL )
4962  {
4963  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4964  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4965  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4966  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4967  }
4968  else if ( sepa != NULL )
4969  {
4970  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4971  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4972  }
4973  else
4974  {
4975  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4976  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4977  }
4978 
4979  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4980  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4981  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4982  for( j = 0; j < nvarsC1; j++ )
4983  {
4984  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4985  }
4986  for( j = 0; j < nvarsC2; j++ )
4987  {
4988  if( liftcoefs[varsC2[j]] > 0 )
4989  {
4990  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4991  }
4992  }
4993  for( j = 0; j < nvarsF; j++ )
4994  {
4995  if( liftcoefs[varsF[j]] > 0 )
4996  {
4997  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4998  }
4999  }
5000  for( j = 0; j < nvarsR; j++ )
5001  {
5002  if( liftcoefs[varsR[j]] > 0 )
5003  {
5004  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5005  }
5006  }
5007  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5008 
5009  /* checks, if cut is violated enough */
5010  if( SCIPisCutEfficacious(scip, sol, row) )
5011  {
5012  if( cons != NULL )
5013  {
5014  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5015  }
5016  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5017  (*ncuts)++;
5018  }
5019  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5020  }
5021 
5022  /* frees temporary memory */
5023  SCIPfreeBufferArray(scip, &liftcoefs);
5024  SCIPfreeBufferArray(scip, &varsR);
5025  SCIPfreeBufferArray(scip, &varsF);
5026  SCIPfreeBufferArray(scip, &varsC2);
5027  SCIPfreeBufferArray(scip, &varsC1);
5028 
5029  return SCIP_OKAY;
5030 }
5031 
5032 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5033 static
5035  SCIP* scip, /**< SCIP data structure */
5036  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5037  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5038  SCIP_VAR** vars, /**< variables in knapsack constraint */
5039  int nvars, /**< number of variables in knapsack constraint */
5040  int ntightened, /**< number of variables with tightened upper bound */
5041  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5042  SCIP_Longint capacity, /**< capacity of knapsack */
5043  SCIP_Real* solvals, /**< solution values of all problem variables */
5044  int* feassetvars, /**< variables in feasible set */
5045  int* nonfeassetvars, /**< variables not in feasible set */
5046  int nfeassetvars, /**< number of variables in feasible set */
5047  int nnonfeassetvars, /**< number of variables not in feasible set */
5048  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5049  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5050  int* ncuts /**< pointer to add up the number of found cuts */
5051  )
5052 {
5053  int* varsT1;
5054  int* varsT2;
5055  int* varsF;
5056  int* varsR;
5057  int* liftcoefs;
5058  SCIP_Real cutact;
5059  int nvarsT1;
5060  int nvarsT2;
5061  int nvarsF;
5062  int nvarsR;
5063  int liftrhs;
5064  int j;
5065 
5066  assert( cutoff != NULL );
5067  *cutoff = FALSE;
5068 
5069  /* allocates temporary memory */
5070  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5071  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5072  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5073  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5074  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5075 
5076  /* 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
5077  * as follows
5078  * T_2 = { j in T : x*_j = 1 } and
5079  * T_1 = T\T_2
5080  */
5081  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5082  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5083 
5084  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5085  if( nvarsT1 == 0 && nvarsT2 > 0)
5086  {
5087  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5088  assert(nvarsT1 == 1);
5089  }
5090  assert(nvarsT2 == 0 || nvarsT1 > 0);
5091 
5092  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5093  * R = { j in N\T : x*_j = 0 } and
5094  * F = (N\T)\F
5095  */
5096  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5097  assert(nvarsF + nvarsR == nnonfeassetvars);
5098  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5099 
5100  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5101  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5102  * is included in the sorting routine)
5103  */
5104  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5105 
5106  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5107  *
5108  * 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 }
5109  *
5110  * 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
5111  *
5112  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5113  *
5114  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5115  * up-lifting for the variabels in R according to the second level lifting sequence
5116  */
5117  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5118  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5119 
5120  /* checks, if lifting yielded a violated cut */
5121  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5122  {
5123  SCIP_ROW* row;
5124  char name[SCIP_MAXSTRLEN];
5125 
5126  /* creates LP row */
5127  assert( cons == NULL || sepa == NULL );
5128  if( cons != NULL )
5129  {
5130  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5131  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5132  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5133  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5134  }
5135  else if ( sepa != NULL )
5136  {
5137  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5138  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5139  }
5140  else
5141  {
5142  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5143  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5144  }
5145 
5146  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5147  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5148  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5149  for( j = 0; j < nvarsT1; j++ )
5150  {
5151  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5152  }
5153  for( j = 0; j < nvarsT2; j++ )
5154  {
5155  if( liftcoefs[varsT2[j]] > 0 )
5156  {
5157  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5158  }
5159  }
5160  for( j = 0; j < nvarsF; j++ )
5161  {
5162  if( liftcoefs[varsF[j]] > 0 )
5163  {
5164  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5165  }
5166  }
5167  for( j = 0; j < nvarsR; j++ )
5168  {
5169  if( liftcoefs[varsR[j]] > 0 )
5170  {
5171  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5172  }
5173  }
5174  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5175 
5176  /* checks, if cut is violated enough */
5177  if( SCIPisCutEfficacious(scip, sol, row) )
5178  {
5179  if( cons != NULL )
5180  {
5181  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5182  }
5183  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5184  (*ncuts)++;
5185  }
5186  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5187  }
5188 
5189  /* frees temporary memory */
5190  SCIPfreeBufferArray(scip, &liftcoefs);
5191  SCIPfreeBufferArray(scip, &varsR);
5192  SCIPfreeBufferArray(scip, &varsF);
5193  SCIPfreeBufferArray(scip, &varsT2);
5194  SCIPfreeBufferArray(scip, &varsT1);
5195 
5196  return SCIP_OKAY;
5197 }
5198 
5199 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5200 static
5202  SCIP* scip, /**< SCIP data structure */
5203  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5204  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5205  SCIP_VAR** vars, /**< variables in knapsack constraint */
5206  int nvars, /**< number of variables in knapsack constraint */
5207  int ntightened, /**< number of variables with tightened upper bound */
5208  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5209  SCIP_Longint capacity, /**< capacity of knapsack */
5210  SCIP_Real* solvals, /**< solution values of all problem variables */
5211  int* mincovervars, /**< mincover variables */
5212  int* nonmincovervars, /**< nonmincover variables */
5213  int nmincovervars, /**< number of mincover variables */
5214  int nnonmincovervars, /**< number of nonmincover variables */
5215  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5216  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5217  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5218  int* ncuts /**< pointer to add up the number of found cuts */
5219  )
5220 {
5221  SCIP_Real* realliftcoefs;
5222  SCIP_Real cutact;
5223  int liftrhs;
5224 
5225  assert( cutoff != NULL );
5226  *cutoff = FALSE;
5227  cutact = 0.0;
5228 
5229  /* allocates temporary memory */
5230  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5231 
5232  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5233  *
5234  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5235  *
5236  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5237  *
5238  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5239  *
5240  * uses superadditive up-lifting for the variables in N\C.
5241  */
5242  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5243  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5244  liftrhs = nmincovervars - 1;
5245 
5246  /* checks, if lifting yielded a violated cut */
5247  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5248  {
5249  SCIP_ROW* row;
5250  char name[SCIP_MAXSTRLEN];
5251  int j;
5252 
5253  /* creates LP row */
5254  assert( cons == NULL || sepa == NULL );
5255  if ( cons != NULL )
5256  {
5257  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5258  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5259  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5260  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5261  }
5262  else if ( sepa != NULL )
5263  {
5264  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5265  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5266  }
5267  else
5268  {
5269  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5270  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5271  }
5272 
5273  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5274  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5275  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5276  for( j = 0; j < nmincovervars; j++ )
5277  {
5278  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5279  }
5280  for( j = 0; j < nnonmincovervars; j++ )
5281  {
5282  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5283  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5284  {
5285  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5286  }
5287  }
5288  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5289 
5290  /* checks, if cut is violated enough */
5291  if( SCIPisCutEfficacious(scip, sol, row) )
5292  {
5293  if( cons != NULL )
5294  {
5295  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5296  }
5297  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5298  (*ncuts)++;
5299  }
5300  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5301  }
5302 
5303  /* frees temporary memory */
5304  SCIPfreeBufferArray(scip, &realliftcoefs);
5305 
5306  return SCIP_OKAY;
5307 }
5308 
5309 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5310  * 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
5311  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5312  * note that all variables with x*_j = 1 will be removed last
5313  */
5314 static
5316  SCIP* scip, /**< SCIP data structure */
5317  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5318  SCIP_Longint capacity, /**< capacity of knapsack */
5319  SCIP_Real* solvals, /**< solution values of all problem variables */
5320  int* covervars, /**< pointer to store cover variables */
5321  int* noncovervars, /**< pointer to store noncover variables */
5322  int* ncovervars, /**< pointer to store number of cover variables */
5323  int* nnoncovervars, /**< pointer to store number of noncover variables */
5324  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5325  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5326  )
5327 {
5328  SORTKEYPAIR** sortkeypairs;
5329  SORTKEYPAIR** sortkeypairssorted;
5330  SCIP_Longint minweight;
5331  int nsortkeypairs;
5332  int minweightidx;
5333  int j;
5334  int k;
5335 
5336  assert(scip != NULL);
5337  assert(covervars != NULL);
5338  assert(noncovervars != NULL);
5339  assert(ncovervars != NULL);
5340  assert(*ncovervars > 0);
5341  assert(nnoncovervars != NULL);
5342  assert(*nnoncovervars >= 0);
5343  assert(coverweight != NULL);
5344  assert(*coverweight > 0);
5345  assert(*coverweight > capacity);
5346 
5347  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5348  * order */
5349  nsortkeypairs = *ncovervars;
5350  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5351  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5352 
5353  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5354  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5355  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5356  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5357  */
5358  assert(*ncovervars == nsortkeypairs);
5359  if( modtransused )
5360  {
5361  for( j = 0; j < *ncovervars; j++ )
5362  {
5363  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5364  sortkeypairssorted[j] = sortkeypairs[j];
5365 
5366  sortkeypairs[j]->key1 = solvals[covervars[j]];
5367  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5368  }
5369  }
5370  else
5371  {
5372  for( j = 0; j < *ncovervars; j++ )
5373  {
5374  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5375  sortkeypairssorted[j] = sortkeypairs[j];
5376 
5377  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5378  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5379  }
5380  }
5381  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5382 
5383  /* gets j' with a_j' = min{ a_j : j in C } */
5384  minweightidx = 0;
5385  minweight = weights[covervars[minweightidx]];
5386  for( j = 1; j < *ncovervars; j++ )
5387  {
5388  if( weights[covervars[j]] <= minweight )
5389  {
5390  minweightidx = j;
5391  minweight = weights[covervars[minweightidx]];
5392  }
5393  }
5394  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5395  assert(minweight > 0 && minweight <= *coverweight);
5396 
5397  j = 0;
5398  /* removes variables from C until the remaining variables form a minimal cover */
5399  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5400  {
5401  assert(minweightidx >= j);
5402  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5403 
5404  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5405  if( (*coverweight) - weights[covervars[j]] <= capacity )
5406  {
5407  ++j;
5408  continue;
5409  }
5410 
5411  /* adds j to N\C */
5412  noncovervars[*nnoncovervars] = covervars[j];
5413  (*nnoncovervars)++;
5414 
5415  /* removes j from C */
5416  (*coverweight) -= weights[covervars[j]];
5417  for( k = j; k < (*ncovervars) - 1; k++ )
5418  covervars[k] = covervars[k+1];
5419  (*ncovervars)--;
5420 
5421  /* updates j' with a_j' = min{ a_j : j in C } */
5422  if( j == minweightidx )
5423  {
5424  minweightidx = 0;
5425  minweight = weights[covervars[minweightidx]];
5426  for( k = 1; k < *ncovervars; k++ )
5427  {
5428  if( weights[covervars[k]] <= minweight )
5429  {
5430  minweightidx = k;
5431  minweight = weights[covervars[minweightidx]];
5432  }
5433  }
5434  assert(minweight > 0 && minweight <= *coverweight);
5435  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5436  }
5437  else
5438  {
5439  assert(minweightidx > j);
5440  minweightidx--;
5441  }
5442  /* j needs to stay the same */
5443  }
5444  assert((*coverweight) > capacity);
5445  assert((*coverweight) - minweight <= capacity);
5446 
5447  /* frees temporary memory */
5448  for( j = nsortkeypairs-1; j >= 0; j-- )
5449  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5450  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5451  SCIPfreeBufferArray(scip, &sortkeypairs);
5452 
5453  return SCIP_OKAY;
5454 }
5455 
5456 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5457  * they were chosen to be in C_init:
5458  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5459  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5460  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5461  * and all subsequent feasible sets.
5462  */
5463 static
5465  SCIP* scip, /**< SCIP data structure */
5466  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5467  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5468  SCIP_VAR** vars, /**< variables in knapsack constraint */
5469  int nvars, /**< number of variables in knapsack constraint */
5470  int ntightened, /**< number of variables with tightened upper bound */
5471  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5472  SCIP_Longint capacity, /**< capacity of knapsack */
5473  SCIP_Real* solvals, /**< solution values of all problem variables */
5474  int* covervars, /**< pointer to store cover variables */
5475  int* noncovervars, /**< pointer to store noncover variables */
5476  int* ncovervars, /**< pointer to store number of cover variables */
5477  int* nnoncovervars, /**< pointer to store number of noncover variables */
5478  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5479  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5480  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5481  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5482  int* ncuts /**< pointer to add up the number of found cuts */
5483  )
5484 {
5485  SCIP_Real* sortkeys;
5486  int j;
5487  int k;
5488 
5489  assert(scip != NULL);
5490  assert(covervars != NULL);
5491  assert(noncovervars != NULL);
5492  assert(ncovervars != NULL);
5493  assert(*ncovervars > 0);
5494  assert(nnoncovervars != NULL);
5495  assert(*nnoncovervars >= 0);
5496  assert(coverweight != NULL);
5497  assert(*coverweight > 0);
5498  assert(*coverweight > capacity);
5499  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5500  assert(cutoff != NULL);
5501 
5502  *cutoff = FALSE;
5503 
5504  /* allocates temporary memory */
5505  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5506 
5507  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5508  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5509  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5510  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5511  */
5512  if( modtransused )
5513  {
5514  for( j = 0; j < *ncovervars; j++ )
5515  {
5516  sortkeys[j] = solvals[covervars[j]];
5517  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5518  }
5519  }
5520  else
5521  {
5522  for( j = 0; j < *ncovervars; j++ )
5523  {
5524  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5525  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5526  }
5527  }
5528  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5529 
5530  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5531  * in addition to an extended weight inequality this gives cardinality inequalities */
5532  while( *ncovervars >= 2 )
5533  {
5534  /* adds first element of C_init to N\C_init */
5535  noncovervars[*nnoncovervars] = covervars[0];
5536  (*nnoncovervars)++;
5537 
5538  /* removes first element from C_init */
5539  (*coverweight) -= weights[covervars[0]];
5540  for( k = 0; k < (*ncovervars) - 1; k++ )
5541  covervars[k] = covervars[k+1];
5542  (*ncovervars)--;
5543 
5544  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5545  if( (*coverweight) <= capacity )
5546  {
5547  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5548  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5549  }
5550 
5551  /* stop if cover is too large */
5552  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5553  break;
5554  }
5555 
5556  /* frees temporary memory */
5557  SCIPfreeBufferArray(scip, &sortkeys);
5558 
5559  return SCIP_OKAY;
5560 }
5561 
5562 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5564  SCIP* scip, /**< SCIP data structure */
5565  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5566  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5567  SCIP_VAR** vars, /**< variables in knapsack constraint */
5568  int nvars, /**< number of variables in knapsack constraint */
5569  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5570  SCIP_Longint capacity, /**< capacity of knapsack */
5571  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5572  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5573  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5574  int* ncuts /**< pointer to add up the number of found cuts */
5575  )
5576 {
5577  SCIP_Real* solvals;
5578  int* covervars;
5579  int* noncovervars;
5580  SCIP_Bool coverfound;
5581  SCIP_Bool fractional;
5582  SCIP_Bool modtransused;
5583  SCIP_Longint coverweight;
5584  int ncovervars;
5585  int nnoncovervars;
5586  int ntightened;
5587 
5588  assert(scip != NULL);
5589  assert(capacity >= 0);
5590  assert(cutoff != NULL);
5591  assert(ncuts != NULL);
5592 
5593  *cutoff = FALSE;
5594 
5595  if( nvars == 0 )
5596  return SCIP_OKAY;
5597 
5598  assert(vars != NULL);
5599  assert(nvars > 0);
5600  assert(weights != NULL);
5601 
5602  /* increase age of constraint (age is reset to zero, if a cut was found) */
5603  if( cons != NULL )
5604  {
5605  SCIP_CALL( SCIPincConsAge(scip, cons) );
5606  }
5607 
5608  /* allocates temporary memory */
5609  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5610  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5611  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5612 
5613  /* gets solution values of all problem variables */
5614  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5615 
5616 #ifdef SCIP_DEBUG
5617  {
5618  int i;
5619 
5620  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5621  cons == NULL ? "-" : SCIPconsGetName(cons));
5622  for( i = 0; i < nvars; ++i )
5623  {
5624  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5625  }
5626  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5627  }
5628 #endif
5629 
5630  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5631  */
5632  if( usegubs )
5633  {
5634  SCIP_GUBSET* gubset;
5635 
5636  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5637 
5638  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5639  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5640 
5641  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5642  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5643  assert(gubset->ngubconss <= nvars);
5644 
5645  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5646  * MODIFIED transformed separation problem and taking into account the following fixing:
5647  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5648  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5649  * if one exists
5650  */
5651  modtransused = TRUE;
5652  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5653  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5654 
5655  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5656 
5657  /* if x* is not fractional we stop the separation routine */
5658  if( !fractional )
5659  {
5660  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5661 
5662  /* frees memory for GUB set data structure */
5663  GUBsetFree(scip, &gubset);
5664 
5665  goto TERMINATE;
5666  }
5667 
5668  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5669  if( coverfound )
5670  {
5671  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5672  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5673  */
5674  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5675  &nnoncovervars, &coverweight, modtransused) );
5676 
5677  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5678  if( gubset->ngubconss < nvars )
5679  {
5680  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5681  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5682  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5683  }
5684  else
5685  {
5686  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5687  * GUB information
5688  */
5689  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5690  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5691  }
5692  }
5693 
5694  /* frees memory for GUB set data structure */
5695  GUBsetFree(scip, &gubset);
5696  }
5697  else
5698  {
5699  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5700  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5701  */
5702 
5703  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5704  * MODIFIED transformed separation problem and taking into account the following fixing:
5705  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5706  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5707  * if one exists
5708  */
5709  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5710  modtransused = TRUE;
5711  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5712  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5713  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5714 
5715  /* if x* is not fractional we stop the separation routine */
5716  if( !fractional )
5717  goto TERMINATE;
5718 
5719  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5720  if( coverfound )
5721  {
5722  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5723  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5724  */
5725  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5726  &nnoncovervars, &coverweight, modtransused) );
5727 
5728  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5729  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5730  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5731 
5732  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5733  {
5734  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5735  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5736  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5737  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5738  }
5739  }
5740  }
5741 
5742  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5743  if ( ! (*cutoff) )
5744  {
5745  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5746  * transformed separation problem and taking into account the following fixing:
5747  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5748  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5749  * if one exists
5750  */
5751  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5752  modtransused = FALSE;
5753  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5754  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5755  assert(fractional);
5756  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5757 
5758  /* if no cover was found we stop the separation routine */
5759  if( coverfound )
5760  {
5761  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5762  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5763  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5764  */
5765  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5766  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5767  }
5768  }
5769 
5770  TERMINATE:
5771  /* frees temporary memory */
5772  SCIPfreeBufferArray(scip, &noncovervars);
5773  SCIPfreeBufferArray(scip, &covervars);
5774  SCIPfreeBufferArray(scip, &solvals);
5775 
5776  return SCIP_OKAY;
5777 }
5778 
5779 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5781  SCIP* scip, /**< SCIP data structure */
5782  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5783  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5784  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5785  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5786  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5787  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5788  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5789  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5790  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5791  int* ncuts /**< pointer to add up the number of found cuts */
5792  )
5793 {
5794  SCIP_VAR** binvars;
5795  SCIP_VAR** consvars;
5796  SCIP_Real* binvals;
5797  SCIP_Longint* consvals;
5798  SCIP_Longint minact;
5799  SCIP_Longint maxact;
5800  SCIP_Real intscalar;
5801  SCIP_Bool success;
5802  int nbinvars;
5803  int nconsvars;
5804  int i;
5805 
5806  int* tmpindices;
5807  int tmp;
5808  SCIP_CONSHDLR* conshdlr;
5809  SCIP_CONSHDLRDATA* conshdlrdata;
5810  SCIP_Bool noknapsackconshdlr;
5811  SCIP_Bool usegubs;
5812 
5813  assert(nknapvars > 0);
5814  assert(knapvars != NULL);
5815  assert(cutoff != NULL);
5816 
5817  tmpindices = NULL;
5818 
5819  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5820  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5821 
5822  binvars = SCIPgetVars(scip);
5823 
5824  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5825  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5826 
5827  *cutoff = FALSE;
5828 
5829  if( nbinvars == 0 )
5830  return SCIP_OKAY;
5831 
5832  /* set up data structures */
5833  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5834  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5835 
5836  /* get conshdlrdata to use cleared memory */
5837  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5838  if( conshdlr == NULL )
5839  {
5840  noknapsackconshdlr = TRUE;
5841  usegubs = DEFAULT_USEGUBS;
5842 
5843  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5844  BMSclearMemoryArray(binvals, nbinvars);
5845  }
5846  else
5847  {
5848  noknapsackconshdlr = FALSE;
5849  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5850  assert(conshdlrdata != NULL);
5851  usegubs = conshdlrdata->usegubs;
5852 
5853  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5854 
5855  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5856  * change their types to SCIP_VARTYPE_BINARY during presolving
5857  */
5858  if( conshdlrdata->reals1size == 0 )
5859  {
5860  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5861  conshdlrdata->reals1size = 1;
5862  conshdlrdata->reals1[0] = 0.0;
5863  }
5864 
5865  assert(conshdlrdata->reals1size > 0);
5866 
5867  /* next if condition should normally not be true, because it means that presolving has created more binary
5868  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5869  * transform all integers into their binary representation then it maybe happens
5870  */
5871  if( conshdlrdata->reals1size < nbinvars )
5872  {
5873  int oldsize = conshdlrdata->reals1size;
5874 
5875  conshdlrdata->reals1size = nbinvars;
5876  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5877  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5878  }
5879  binvals = conshdlrdata->reals1;
5880 
5881  /* check for cleared array, all entries have to be zero */
5882 #ifndef NDEBUG
5883  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5884  {
5885  assert(binvals[tmp] == 0);
5886  }
5887 #endif
5888  }
5889 
5890  tmp = 0;
5891 
5892  /* relax continuous knapsack constraint:
5893  * 1. make all variables binary:
5894  * if x_j is continuous or integer variable substitute:
5895  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5896  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5897  * 2. convert coefficients of all variables to positive integers:
5898  * - scale all coefficients a_j to a~_j integral
5899  * - substitute x~_j = 1 - x_j if a~_j < 0
5900  */
5901 
5902  /* replace integer and continuous variables with binary variables */
5903  for( i = 0; i < nknapvars; i++ )
5904  {
5905  SCIP_VAR* var;
5906 
5907  var = knapvars[i];
5908 
5909  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5910  {
5911  SCIP_Real solval;
5912  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5913 
5914  solval = SCIPgetSolVal(scip, sol, var);
5915 
5916  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5917  if( SCIPisFeasLT(scip, solval, 0.0 )
5918  || SCIPisFeasGT(scip, solval, 1.0) )
5919  {
5920  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5921  solval, SCIPvarGetName(var));
5922  goto TERMINATE;
5923  }
5924 
5925  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5926  if( !noknapsackconshdlr )
5927  {
5928  assert(tmpindices != NULL);
5929 
5930  tmpindices[tmp] = SCIPvarGetProbindex(var);
5931  ++tmp;
5932  }
5933  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5934  }
5935  else if( valscale * knapvals[i] > 0.0 )
5936  {
5937  SCIP_VAR** zvlb;
5938  SCIP_Real* bvlb;
5939  SCIP_Real* dvlb;
5940  SCIP_Real bestlbsol;
5941  int bestlbtype;
5942  int nvlb;
5943  int j;
5944 
5945  /* a_j > 0: substitution with lb or vlb */
5946  nvlb = SCIPvarGetNVlbs(var);
5947  zvlb = SCIPvarGetVlbVars(var);
5948  bvlb = SCIPvarGetVlbCoefs(var);
5949  dvlb = SCIPvarGetVlbConstants(var);
5950 
5951  /* search for lb or vlb with maximal bound value */
5952  bestlbsol = SCIPvarGetLbGlobal(var);
5953  bestlbtype = -1;
5954  for( j = 0; j < nvlb; j++ )
5955  {
5956  /* use only numerical stable vlb with binary variable z */
5957  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5958  {
5959  SCIP_Real vlbsol;
5960 
5961  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5962  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5963  {
5964  *cutoff = TRUE;
5965  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5967  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5968  goto TERMINATE;
5969  }
5970 
5971  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5972  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5973  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5974  {
5975  bestlbsol = vlbsol;
5976  bestlbtype = j;
5977  }
5978  }
5979  }
5980 
5981  /* if no lb or vlb with binary variable was found, we have to abort */
5982  if( SCIPisInfinity(scip, -bestlbsol) )
5983  goto TERMINATE;
5984 
5985  if( bestlbtype == -1 )
5986  {
5987  rhs -= valscale * knapvals[i] * bestlbsol;
5988  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5989  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5990  }
5991  else
5992  {
5993  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5994  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5995  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5996 
5997  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5998  goto TERMINATE;
5999 
6000  if( !noknapsackconshdlr )
6001  {
6002  assert(tmpindices != NULL);
6003 
6004  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6005  ++tmp;
6006  }
6007  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6008  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6009  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6010  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6011  }
6012  }
6013  else
6014  {
6015  SCIP_VAR** zvub;
6016  SCIP_Real* bvub;
6017  SCIP_Real* dvub;
6018  SCIP_Real bestubsol;
6019  int bestubtype;
6020  int nvub;
6021  int j;
6022 
6023  assert(valscale * knapvals[i] < 0.0);
6024 
6025  /* a_j < 0: substitution with ub or vub */
6026  nvub = SCIPvarGetNVubs(var);
6027  zvub = SCIPvarGetVubVars(var);
6028  bvub = SCIPvarGetVubCoefs(var);
6029  dvub = SCIPvarGetVubConstants(var);
6030 
6031  /* search for ub or vub with minimal bound value */
6032  bestubsol = SCIPvarGetUbGlobal(var);
6033  bestubtype = -1;
6034  for( j = 0; j < nvub; j++ )
6035  {
6036  /* use only numerical stable vub with active binary variable z */
6037  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6038  {
6039  SCIP_Real vubsol;
6040 
6041  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6042  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6043  {
6044  *cutoff = TRUE;
6045  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6047  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6048  goto TERMINATE;
6049  }
6050 
6051  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6052  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6053  if( SCIPisLE(scip, vubsol, bestubsol) )
6054  {
6055  bestubsol = vubsol;
6056  bestubtype = j;
6057  }
6058  }
6059  }
6060 
6061  /* if no ub or vub with binary variable was found, we have to abort */
6062  if( SCIPisInfinity(scip, bestubsol) )
6063  goto TERMINATE;
6064 
6065  if( bestubtype == -1 )
6066  {
6067  rhs -= valscale * knapvals[i] * bestubsol;
6068  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6069  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6070  }
6071  else
6072  {
6073  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6074  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6075  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6076 
6077  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6078  goto TERMINATE;
6079 
6080  if( !noknapsackconshdlr )
6081  {
6082  assert(tmpindices != NULL);
6083 
6084  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6085  ++tmp;
6086  }
6087  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6088  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6089  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6090  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6091  }
6092  }
6093  }
6094 
6095  /* convert coefficients of all (now binary) variables to positive integers:
6096  * - make all coefficients integral
6097  * - make all coefficients positive (substitute negated variable)
6098  */
6099  nconsvars = 0;
6100 
6101  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6102  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6103  */
6105  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6106  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6107 
6108  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6109  if( !success )
6110  intscalar = 1.0;
6111 
6112  /* make all coefficients integral and positive:
6113  * - scale a~_j = a_j * intscalar
6114  * - substitute x~_j = 1 - x_j if a~_j < 0
6115  */
6116  rhs = rhs * intscalar;
6117 
6118  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6119  minact = 0;
6120  maxact = 0;
6121  for( i = 0; i < nbinvars; i++ )
6122  {
6123  SCIP_VAR* var;
6124  SCIP_Longint val;
6125 
6126  val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6127  if( val == 0 )
6128  continue;
6129 
6130  if( val > 0 )
6131  {
6132  var = binvars[i];
6133  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6134  val, SCIPvarGetName(var), binvals[i], rhs);
6135  }
6136  else
6137  {
6138  assert(val < 0);
6139 
6140  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6141  val = -val; /*lint !e2704*/
6142  rhs += val;
6143  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6144  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6145  }
6146 
6147  if( SCIPvarGetLbLocal(var) > 0.5 )
6148  minact += val;
6149  if( SCIPvarGetUbLocal(var) > 0.5 )
6150  maxact += val;
6151  consvals[nconsvars] = val;
6152  consvars[nconsvars] = var;
6153  nconsvars++;
6154  }
6155 
6156  if( nconsvars > 0 )
6157  {
6158  SCIP_Longint capacity;
6159 
6160  assert(consvars != NULL);
6161  assert(consvals != NULL);
6162  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6163 
6164 #ifdef SCIP_DEBUG
6165  {
6166  SCIP_Real act;
6167 
6168  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6169  act = 0.0;
6170  for( i = 0; i < nconsvars; ++i )
6171  {
6172  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6173  SCIPgetSolVal(scip, sol, consvars[i]));
6174  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6175  }
6176  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6177  capacity, rhs, act, minact, maxact);
6178  }
6179 #endif
6180 
6181  if( minact > capacity )
6182  {
6183  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6184  *cutoff = TRUE;
6185  goto TERMINATE;
6186  }
6187 
6188  if( maxact > capacity )
6189  {
6190  /* separate lifted cut from relaxed knapsack constraint */
6191  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6192  }
6193  }
6194 
6195  TERMINATE:
6196  /* free data structures */
6197  if( noknapsackconshdlr)
6198  {
6199  SCIPfreeBufferArray(scip, &binvals);
6200  }
6201  else
6202  {
6203  /* clear binvals */
6204  for( --tmp; tmp >= 0; --tmp)
6205  {
6206  assert(tmpindices != NULL);
6207  binvals[tmpindices[tmp]] = 0;
6208  }
6209  SCIPfreeBufferArray(scip, &tmpindices);
6210  }
6211  SCIPfreeBufferArray(scip, &consvals);
6212  SCIPfreeBufferArray(scip, &consvars);
6213 
6214  return SCIP_OKAY;
6215 }
6216 
6217 /** separates given knapsack constraint */
6218 static
6220  SCIP* scip, /**< SCIP data structure */
6221  SCIP_CONS* cons, /**< knapsack constraint */
6222  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6223  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6224  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6225  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6226  int* ncuts /**< pointer to add up the number of found cuts */
6227  )
6228 {
6229  SCIP_CONSDATA* consdata;
6230  SCIP_Bool violated;
6231 
6232  assert(ncuts != NULL);
6233  assert(cutoff != NULL);
6234  *cutoff = FALSE;
6235 
6236  consdata = SCIPconsGetData(cons);
6237  assert(consdata != NULL);
6238 
6239  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6240 
6241  /* check knapsack constraint itself for feasibility */
6242  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6243 
6244  if( violated )
6245  {
6246  /* add knapsack constraint as LP row to the LP */
6247  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6248  (*ncuts)++;
6249  }
6250  else if( sepacuts )
6251  {
6252  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6253  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6254  }
6255 
6256  return SCIP_OKAY;
6257 }
6258 
6259 /** adds coefficient to constraint data */
6260 static
6262  SCIP* scip, /**< SCIP data structure */
6263  SCIP_CONS* cons, /**< knapsack constraint */
6264  SCIP_VAR* var, /**< variable to add to knapsack */
6265  SCIP_Longint weight /**< weight of variable in knapsack */
6266  )
6267 {
6268  SCIP_CONSDATA* consdata;
6270  consdata = SCIPconsGetData(cons);
6271  assert(consdata != NULL);
6272  assert(SCIPvarIsBinary(var));
6273  assert(weight > 0);
6274 
6275  /* add the new coefficient to the LP row */
6276  if( consdata->row != NULL )
6277  {
6278  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6279  }
6280 
6281  /* check for fixed variable */
6282  if( SCIPvarGetLbGlobal(var) > 0.5 )
6283  {
6284  /* variable is fixed to one: reduce capacity */
6285  consdata->capacity -= weight;
6286  }
6287  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6288  {
6289  SCIP_Bool negated;
6290 
6291  /* get binary representative of variable */
6292  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6293 
6294  /* insert coefficient */
6295  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6296  consdata->vars[consdata->nvars] = var;
6297  consdata->weights[consdata->nvars] = weight;
6298  consdata->nvars++;
6299 
6300  /* capture variable */
6301  SCIP_CALL( SCIPcaptureVar(scip, var) );
6302 
6303  /* install the rounding locks of variable */
6304  SCIP_CALL( lockRounding(scip, cons, var) );
6305 
6306  /* catch events */
6307  if( SCIPconsIsTransformed(cons) )
6308  {
6309  SCIP_CONSHDLRDATA* conshdlrdata;
6310 
6311  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6312  assert(conshdlrdata != NULL);
6313  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6315  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6316  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6317 
6318  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6319  consdata->existmultaggr = TRUE;
6320 
6321  /* mark constraint to be propagated and presolved */
6322  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6323  consdata->presolvedtiming = 0;
6324  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6325  }
6326 
6327  /* update weight sums */
6328  updateWeightSums(consdata, var, weight);
6329 
6330  consdata->sorted = FALSE;
6331  consdata->cliquepartitioned = FALSE;
6332  consdata->negcliquepartitioned = FALSE;
6333  consdata->merged = FALSE;
6334  }
6335 
6336  return SCIP_OKAY;
6337 }
6338 
6339 /** deletes coefficient at given position from constraint data */
6340 static
6342  SCIP* scip, /**< SCIP data structure */
6343  SCIP_CONS* cons, /**< knapsack constraint */
6344  int pos /**< position of coefficient to delete */
6345  )
6346 {
6347  SCIP_CONSDATA* consdata;
6348  SCIP_VAR* var;
6350  consdata = SCIPconsGetData(cons);
6351  assert(consdata != NULL);
6352  assert(0 <= pos && pos < consdata->nvars);
6353 
6354  var = consdata->vars[pos];
6355  assert(var != NULL);
6356  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6357 
6358  /* delete the coefficient from the LP row */
6359  if( consdata->row != NULL )
6360  {
6361  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6362  }
6363 
6364  /* remove the rounding locks of variable */
6365  SCIP_CALL( unlockRounding(scip, cons, var) );
6366 
6367  /* drop events and mark constraint to be propagated and presolved */
6368  if( SCIPconsIsTransformed(cons) )
6369  {
6370  SCIP_CONSHDLRDATA* conshdlrdata;
6371 
6372  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6373  assert(conshdlrdata != NULL);
6375  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6376  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6377 
6378  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6379  consdata->presolvedtiming = 0;
6380  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6381  }
6382 
6383  /* decrease weight sums */
6384  updateWeightSums(consdata, var, -consdata->weights[pos]);
6385 
6386  /* move the last variable to the free slot */
6387  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6388  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6389  if( consdata->eventdata != NULL )
6390  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6391 
6392  /* release variable */
6393  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6394 
6395  /* try to use old clique partitions */
6396  if( consdata->cliquepartitioned )
6397  {
6398  assert(consdata->cliquepartition != NULL);
6399  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6400  * change the clique number */
6401  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6402  {
6403  int oldcliqenum;
6404 
6405  oldcliqenum = consdata->cliquepartition[pos];
6406  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6407 
6408  /* the following if and else cases assure that we have increasing clique numbers */
6409  if( consdata->cliquepartition[pos] > pos )
6410  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6411  else
6412  {
6413  int i;
6414  int cliquenumbefore;
6415 
6416  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6417  * occurs the same as the old one is still in the cliquepartition */
6418  if( oldcliqenum > consdata->cliquepartition[pos] )
6419  {
6420  for( i = 0; i < consdata->nvars; ++i )
6421  if( oldcliqenum == consdata->cliquepartition[i] )
6422  break;
6423  else if( oldcliqenum < consdata->cliquepartition[i] )
6424  {
6425  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6426  break;
6427  }
6428  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6429  * the biggest index, so decrease the number of cliques
6430  */
6431  if( i == consdata->nvars )
6432  --(consdata->ncliques);
6433  }
6434  /* if the old clique number was smaller than the new one we have to check the front for an element with
6435  * clique number minus 1 */
6436  else if( oldcliqenum < consdata->cliquepartition[pos] )
6437  {
6438  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6439  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6440 
6441  if( i < cliquenumbefore )
6442  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6443  }
6444  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6445  else if( pos == consdata->nvars - 1)
6446  {
6447  cliquenumbefore = consdata->cliquepartition[pos];
6448  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6449 
6450  if( i < cliquenumbefore )
6451  --(consdata->ncliques);
6452  }
6453  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6454  }
6455  }
6456  else
6457  --(consdata->ncliques);
6458  }
6459 
6460  if( consdata->negcliquepartitioned )
6461  {
6462  assert(consdata->negcliquepartition != NULL);
6463  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6464  * change the clique number */
6465  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6466  {
6467  int oldcliqenum;
6468 
6469  oldcliqenum = consdata->negcliquepartition[pos];
6470  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6471 
6472  /* the following if and else cases assure that we have increasing clique numbers */
6473  if( consdata->negcliquepartition[pos] > pos )
6474  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6475  else
6476  {
6477  int i;
6478  int cliquenumbefore;
6479 
6480  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6481  * occurs, the same as the old one occurs */
6482  if( oldcliqenum > consdata->negcliquepartition[pos] )
6483  {
6484  for( i = 0; i < consdata->nvars; ++i )
6485  if( oldcliqenum == consdata->negcliquepartition[i] )
6486  break;
6487  else if( oldcliqenum < consdata->negcliquepartition[i] )
6488  {
6489  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6490  break;
6491  }
6492  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6493  * the biggest index, so decrease the number of negated cliques
6494  */
6495  if( i == consdata->nvars )
6496  --(consdata->nnegcliques);
6497  }
6498  /* if the old clique number was smaller than the new one we have to check the front for an element with
6499  * clique number minus 1 */
6500  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6501  {
6502  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6503  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6504 
6505  if( i < cliquenumbefore )
6506  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6507  }
6508  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6509  else if( pos == consdata->nvars - 1)
6510  {
6511  cliquenumbefore = consdata->negcliquepartition[pos];
6512  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6513 
6514  if( i < cliquenumbefore )
6515  --(consdata->nnegcliques);
6516  }
6517  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6518  }
6519  }
6520  else
6521  --(consdata->nnegcliques);
6522  }
6523 
6524  --(consdata->nvars);
6525 
6526  return SCIP_OKAY;
6527 }
6528 
6529 /** removes all items with weight zero from knapsack constraint */
6530 static
6532  SCIP* scip, /**< SCIP data structure */
6533  SCIP_CONS* cons /**< knapsack constraint */
6534  )
6535 {
6536  SCIP_CONSDATA* consdata;
6537  int v;
6538 
6539  consdata = SCIPconsGetData(cons);
6540  assert(consdata != NULL);
6541 
6542  for( v = consdata->nvars-1; v >= 0; --v )
6543  {
6544  if( consdata->weights[v] == 0 )
6545  {
6546  SCIP_CALL( delCoefPos(scip, cons, v) );
6547  }
6548  }
6549 
6550  return SCIP_OKAY;
6551 }
6552 
6553 /* perform deletion of variables in all constraints of the constraint handler */
6554 static
6556  SCIP* scip, /**< SCIP data structure */
6557  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6558  SCIP_CONS** conss, /**< array of constraints */
6559  int nconss /**< number of constraints */
6560  )
6561 {
6562  SCIP_CONSDATA* consdata;
6563  int i;
6564  int v;
6565 
6566  assert(scip != NULL);
6567  assert(conshdlr != NULL);
6568  assert(conss != NULL);
6569  assert(nconss >= 0);
6570  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6571 
6572  /* iterate over all constraints */
6573  for( i = 0; i < nconss; i++ )
6574  {
6575  consdata = SCIPconsGetData(conss[i]);
6576 
6577  /* constraint is marked, that some of its variables were deleted */
6578  if( consdata->varsdeleted )
6579  {
6580  /* iterate over all variables of the constraint and delete them from the constraint */
6581  for( v = consdata->nvars - 1; v >= 0; --v )
6582  {
6583  if( SCIPvarIsDeleted(consdata->vars[v]) )
6584  {
6585  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6586  }
6587  }
6588  consdata->varsdeleted = FALSE;
6589  }
6590  }
6591 
6592  return SCIP_OKAY;
6593 }
6594 
6595 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6596 static
6598  SCIP* scip, /**< SCIP data structure */
6599  SCIP_CONS* cons, /**< knapsack constraint */
6600  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6601  )
6602 {
6603  SCIP_CONSDATA* consdata;
6604  int v;
6605  int prev;
6606 
6607  assert(scip != NULL);
6608  assert(cons != NULL);
6609  assert(cutoff != NULL);
6610 
6611  consdata = SCIPconsGetData(cons);
6612  assert(consdata != NULL);
6613 
6614  *cutoff = FALSE;
6615 
6616  if( consdata->merged )
6617  return SCIP_OKAY;
6618 
6619  if( consdata->nvars <= 1 )
6620  {
6621  consdata->merged = TRUE;
6622  return SCIP_OKAY;
6623  }
6624 
6625  assert(consdata->vars != NULL || consdata->nvars == 0);
6626 
6627  /* sorting array after indices of variables, that's only for faster merging */
6628  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6629  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6630 
6631  /* knapsack-sorting (decreasing weights) now lost */
6632  consdata->sorted = FALSE;
6633 
6634  v = consdata->nvars - 1;
6635  prev = v - 1;
6636  /* loop backwards through the items: deletion only affects rear items */
6637  while( prev >= 0 )
6638  {
6639  SCIP_VAR* var1;
6640  SCIP_VAR* var2;
6641  SCIP_Bool negated1;
6642  SCIP_Bool negated2;
6643 
6644  negated1 = FALSE;
6645  negated2 = FALSE;
6646 
6647  var1 = consdata->vars[v];
6648  assert(SCIPvarIsBinary(var1));
6649  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6651  {
6652  var1 = SCIPvarGetNegatedVar(var1);
6653  negated1 = TRUE;
6654  }
6655  assert(var1 != NULL);
6656 
6657  var2 = consdata->vars[prev];
6658  assert(SCIPvarIsBinary(var2));
6659  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6661  {
6662  var2 = SCIPvarGetNegatedVar(var2);
6663  negated2 = TRUE;
6664  }
6665  assert(var2 != NULL);
6666 
6667  if( var1 == var2 )
6668  {
6669  /* both variables are either active or negated */
6670  if( negated1 == negated2 )
6671  {
6672  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6673  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6674  SCIP_CALL( delCoefPos(scip, cons, v) );
6675  }
6676  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6677  * and delete item of smaller weight
6678  */
6679  else if( consdata->weights[v] == consdata->weights[prev] )
6680  {
6681  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6682  consdata->capacity -= consdata->weights[v];
6683  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6684  SCIP_CALL( delCoefPos(scip, cons, prev) );
6685 
6686  --prev;
6687  }
6688  else if( consdata->weights[v] < consdata->weights[prev] )
6689  {
6690  consdata->capacity -= consdata->weights[v];
6691  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6692  assert(consdata->weights[prev] > 0);
6693  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6694  }
6695  else
6696  {
6697  consdata->capacity -= consdata->weights[prev];
6698  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6699  assert(consdata->weights[v] > 0);
6700  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6701  /* restore order iff necessary */
6702  if( consdata->nvars != v ) /* otherwise the order still stands */
6703  {
6704  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6705  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6706  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6707  --prev;
6708  else /* we need to let v at the same position*/
6709  {
6710  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6711  /* don't decrease v, the same variable may exist up front */
6712  --prev;
6713  continue;
6714  }
6715  }
6716  }
6717  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6718  }
6719  v = prev;
6720  --prev;
6721  }
6722 
6723  consdata->merged = TRUE;
6724 
6725  /* check infeasibility */
6726  if( consdata->onesweightsum > consdata->capacity )
6727  {
6728  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6729  *cutoff = TRUE;
6730  return SCIP_OKAY;
6731  }
6732 
6733  return SCIP_OKAY;
6734 }
6735 
6736 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6737  * fixings (dual reductions)
6738  */
6739 static
6741  SCIP* scip, /**< SCIP data structure */
6742  SCIP_CONS* cons, /**< knapsack constraint */
6743  int* nfixedvars, /**< pointer to count number of fixings */
6744  int* ndelconss, /**< pointer to count number of deleted constraints */
6745  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6746  )
6747 {
6748  SCIP_CONSDATA* consdata;
6749  SCIP_VAR** vars;
6750  SCIP_Real* profits;
6751  int* solitems;
6752  int* nonsolitems;
6753  int* items;
6754  SCIP_Real solval;
6755  SCIP_Bool infeasible;
6756  SCIP_Bool tightened;
6757  SCIP_Bool applicable;
6758  int nsolitems;
6759  int nnonsolitems;
6760  int nvars;
6761  int v;
6762 
6763  assert(!SCIPconsIsModifiable(cons));
6764 
6765  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6766  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6767  * added to the problems have the check flag set to FALSE
6768  */
6769  if( !SCIPconsIsChecked(cons) )
6770  return SCIP_OKAY;
6771 
6772  consdata = SCIPconsGetData(cons);
6773  assert(consdata != NULL);
6774 
6775  nvars = consdata->nvars;
6776  vars = consdata->vars;
6777 
6778  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6779  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6780  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6781  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6782 
6783  applicable = TRUE;
6784 
6785  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6786  * collect object values which are the profits of the knapsack problem
6787  */
6788  for( v = 0; v < nvars; ++v )
6789  {
6790  SCIP_VAR* var;
6791  SCIP_Bool negated;
6792 
6793  var = vars[v];
6794  assert(var != NULL);
6795 
6796  /* the variable should not be (globally) fixed */
6797  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6798 
6801  {
6802  applicable = FALSE;
6803  break;
6804  }
6805 
6806  negated = FALSE;
6807 
6808  /* get the active variable */
6809  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6810  assert(SCIPvarIsActive(var));
6811 
6812  if( negated )
6813  profits[v] = SCIPvarGetObj(var);
6814  else
6815  profits[v] = -SCIPvarGetObj(var);
6816 
6817  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6818  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6819  items[v] = v;
6820  }
6821 
6822  if( applicable )
6823  {
6824  SCIP_Bool success;
6825 
6826  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6827  SCIPdebugPrintCons(scip, cons, NULL);
6828 
6829  /* solve knapsack problem exactly */
6830  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6831  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6832 
6833  if( success )
6834  {
6835  SCIP_VAR* var;
6836 
6837  /* apply solution of the knapsack as dual reductions */
6838  for( v = 0; v < nsolitems; ++v )
6839  {
6840  var = vars[solitems[v]];
6841  assert(var != NULL);
6842 
6843  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6845  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6846  assert(!infeasible);
6847  assert(tightened);
6848  (*nfixedvars)++;
6849  }
6850 
6851  for( v = 0; v < nnonsolitems; ++v )
6852  {
6853  var = vars[nonsolitems[v]];
6854  assert(var != NULL);
6855 
6856  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6858  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6859  assert(!infeasible);
6860  assert(tightened);
6861  (*nfixedvars)++;
6862  }
6863 
6864  SCIP_CALL( SCIPdelCons(scip, cons) );
6865  (*ndelconss)++;
6866  (*deleted) = TRUE;
6867  }
6868  }
6869 
6870  SCIPfreeBufferArray(scip, &nonsolitems);
6871  SCIPfreeBufferArray(scip, &solitems);
6872  SCIPfreeBufferArray(scip, &items);
6873  SCIPfreeBufferArray(scip, &profits);
6874 
6875  return SCIP_OKAY;
6876 }
6877 
6878 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6879  * constraint enters the LP by setting the initial and separated flag to FALSE
6880  */
6881 static
6883  SCIP* scip, /**< SCIP data structure */
6884  SCIP_CONS* cons, /**< knapsack constraint */
6885  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6886  )
6887 {
6888  SCIP_CONSDATA* consdata;
6889  SCIP_VAR** vars;
6890  SCIP_VAR* var;
6891  SCIP_Real offset;
6892  SCIP_Real scale;
6893  SCIP_Real objval;
6894  SCIP_Bool applicable;
6895  SCIP_Bool negated;
6896  int nobjvars;
6897  int nvars;
6898  int v;
6899 
6900  assert(scip != NULL);
6901  assert(cons != NULL);
6902  assert(conshdlrdata != NULL);
6903 
6904  consdata = SCIPconsGetData(cons);
6905  assert(consdata != NULL);
6906 
6907  nvars = consdata->nvars;
6908  nobjvars = SCIPgetNObjVars(scip);
6909 
6910  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6911  * and/or separated flag is set to FALSE
6912  */
6913  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6914  return SCIP_OKAY;
6915 
6916  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6917  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6918  */
6919  if( nobjvars == 0 )
6920  return SCIP_OKAY;
6921 
6922  vars = consdata->vars;
6923  assert(vars != NULL);
6924 
6925  applicable = TRUE;
6926  offset = 0.0;
6927  scale = 1.0;
6928 
6929  for( v = 0; v < nvars && applicable; ++v )
6930  {
6931  negated = FALSE;
6932  var = vars[v];
6933  assert(var != NULL);
6934 
6935  if( SCIPvarIsNegated(var) )
6936  {
6937  negated = TRUE;
6938  var = SCIPvarGetNegatedVar(var);
6939  assert(var != NULL);
6940  }
6941 
6942  objval = SCIPvarGetObj(var);
6943 
6944  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6945  if( SCIPisZero(scip, objval) )
6946  applicable = FALSE;
6947  else
6948  {
6949  SCIP_Real weight;
6950 
6951  weight = (SCIP_Real)consdata->weights[v];
6952 
6953  if( negated )
6954  {
6955  if( v == 0 )
6956  {
6957  /* the first variable defines the scale */
6958  scale = weight / -objval;
6959 
6960  offset += weight;
6961  }
6962  else if( SCIPisEQ(scip, -objval * scale, weight) )
6963  offset += weight;
6964  else
6965  applicable = FALSE;
6966  }
6967  else if( v == 0 )
6968  {
6969  /* the first variable define the scale */
6970  scale = weight / objval;
6971  }
6972  else if( !SCIPisEQ(scip, objval * scale, weight) )
6973  applicable = FALSE;
6974  }
6975  }
6976 
6977  if( applicable )
6978  {
6979  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6980  {
6981  SCIP_Real cutoffbound;
6982 
6983  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6984  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6985  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6986 
6987  cutoffbound = (consdata->capacity - offset) / scale;
6988 
6989  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6990  SCIPconsGetName(cons), cutoffbound);
6991 
6992  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6993  * still excepted
6994  */
6995  cutoffbound += SCIPcutoffbounddelta(scip);
6996 
6997  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6998  SCIPconsGetName(cons), cutoffbound);
6999 
7000  if( cutoffbound < SCIPgetCutoffbound(scip) )
7001  {
7002  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7003 
7004  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7005  }
7006  else
7007  {
7008  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7009  * propagation
7010  */
7011  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
7012  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
7013  }
7014  }
7015  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7016  {
7017  SCIP_Real lowerbound;
7018 
7019  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7020  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
7021  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
7022 
7023  lowerbound = (consdata->capacity - offset) / scale;
7024 
7025  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7026  SCIPconsGetName(cons), lowerbound);
7027 
7028  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
7029  }
7030  }
7031 
7032  return SCIP_OKAY;
7033 }
7034 
7035 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7036  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7037 static
7039  SCIP* scip, /**< SCIP data structure */
7040  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7041  SCIP_VAR** vars, /**< array for sorted variables */
7042  SCIP_Longint* weights, /**< array for sorted weights */
7043  int* cliquestartposs, /**< starting position array for each clique */
7044  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7045  )
7046 {
7047  SCIP_VAR** origvars;
7048  int norigvars;
7049  SCIP_Longint* origweights;
7050  int* cliquepartition;
7051  int ncliques;
7052 
7053  SCIP_VAR*** varpointers;
7054  SCIP_Longint** weightpointers;
7055  int* cliquecount;
7056 
7057  int nextpos;
7058  int c;
7059  int v;
7060 
7061  assert(scip != NULL);
7062  assert(consdata != NULL);
7063  assert(vars != NULL);
7064  assert(weights != NULL);
7065  assert(cliquestartposs != NULL);
7066 
7067  origweights = consdata->weights;
7068  origvars = consdata->vars;
7069  norigvars = consdata->nvars;
7070 
7071  assert(origvars != NULL || norigvars == 0);
7072  assert(origweights != NULL || norigvars == 0);
7073 
7074  if( norigvars == 0 )
7075  return SCIP_OKAY;
7076 
7077  if( usenegatedclique )
7078  {
7079  assert(consdata->negcliquepartitioned);
7080 
7081  cliquepartition = consdata->negcliquepartition;
7082  ncliques = consdata->nnegcliques;
7083  }
7084  else
7085  {
7086  assert(consdata->cliquepartitioned);
7087 
7088  cliquepartition = consdata->cliquepartition;
7089  ncliques = consdata->ncliques;
7090  }
7091 
7092  assert(cliquepartition != NULL);
7093  assert(ncliques > 0);
7094 
7095  /* we first count all clique items and alloc temporary memory for a bucket sort */
7096  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7097  BMSclearMemoryArray(cliquecount, ncliques);
7098 
7099  /* first we count for each clique the number of elements */
7100  for( v = norigvars - 1; v >= 0; --v )
7101  {
7102  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7103  ++(cliquecount[cliquepartition[v]]);
7104  }
7105 
7106  /*@todo: maybe it is better to put largest cliques up front */
7107 
7108 #ifndef NDEBUG
7109  BMSclearMemoryArray(vars, norigvars);
7110  BMSclearMemoryArray(weights, norigvars);
7111 #endif
7112  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7113  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7114 
7115  nextpos = 0;
7116  /* now we initialize all start pointers for each clique, so they will be ordered */
7117  for( c = 0; c < ncliques; ++c )
7118  {
7119  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7120  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7121  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7122  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7123  * vars[7]
7124  *
7125  */
7126  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7127  cliquestartposs[c] = nextpos;
7128  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7129  assert(cliquecount[c] > 0);
7130  nextpos += cliquecount[c];
7131  assert(nextpos > 0);
7132  }
7133  assert(nextpos == norigvars);
7134  cliquestartposs[c] = nextpos;
7135 
7136  /* now we copy all variable and weights to the right order */
7137  for( v = 0; v < norigvars; ++v )
7138  {
7139  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7140  ++(varpointers[cliquepartition[v]]);
7141  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7142  ++(weightpointers[cliquepartition[v]]);
7143  }
7144 #ifndef NDEBUG
7145  for( v = 0; v < norigvars; ++v )
7146  {
7147  assert(vars[v] != NULL);
7148  assert(weights[v] > 0);
7149  }
7150 #endif
7151 
7152  /* free temporary memory */
7153  SCIPfreeBufferArray(scip, &weightpointers);
7154  SCIPfreeBufferArray(scip, &varpointers);
7155  SCIPfreeBufferArray(scip, &cliquecount);
7156 
7157  return SCIP_OKAY;
7158 }
7159 
7160 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7161 static
7163  SCIP* scip, /**< SCIP data structure */
7164  SCIP_CONS* cons, /**< knapsack constraint */
7165  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7166  * information is not needed; in this case, we apply all fixings
7167  * instead of stopping after the first infeasible one */
7168  )
7169 {
7170  SCIP_CONSDATA* consdata;
7171  int v;
7172 
7173  assert(scip != NULL);
7174  assert(cons != NULL);
7175 
7176  consdata = SCIPconsGetData(cons);
7177  assert(consdata != NULL);
7178  assert(consdata->nvars == 0 || consdata->vars != NULL);
7179 
7180  if( cutoff != NULL )
7181  *cutoff = FALSE;
7182 
7183  SCIPdebugMsg(scip, "apply fixings:\n");
7184  SCIPdebugPrintCons(scip, cons, NULL);
7185 
7186  /* check infeasibility */
7187  if ( consdata->onesweightsum > consdata->capacity )
7188  {
7189  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7190 
7191  if( cutoff != NULL )
7192  *cutoff = TRUE;
7193 
7194  return SCIP_OKAY;
7195  }
7196 
7197  /* all multi-aggregations should be resolved */
7198  consdata->existmultaggr = FALSE;
7199 
7200  v = 0;
7201  while( v < consdata->nvars )
7202  {
7203  SCIP_VAR* var;
7204 
7205  var = consdata->vars[v];
7206  assert(SCIPvarIsBinary(var));
7207 
7208  if( SCIPvarGetLbGlobal(var) > 0.5 )
7209  {
7210  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7211  consdata->capacity -= consdata->weights[v];
7212  SCIP_CALL( delCoefPos(scip, cons, v) );
7213  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7214  }
7215  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7216  {
7217  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7218  SCIP_CALL( delCoefPos(scip, cons, v) );
7219  }
7220  else
7221  {
7222  SCIP_VAR* repvar;
7223  SCIP_VAR* negvar;
7224  SCIP_VAR* workvar;
7225  SCIP_Longint weight;
7226  SCIP_Bool negated;
7227 
7228  weight = consdata->weights[v];
7229 
7230  /* get binary representative of variable */
7231  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7232  assert(repvar != NULL);
7233 
7234  /* check for multi-aggregation */
7235  if( SCIPvarIsNegated(repvar) )
7236  {
7237  workvar = SCIPvarGetNegatedVar(repvar);
7238  assert(workvar != NULL);
7239  negated = TRUE;
7240  }
7241  else
7242  {
7243  workvar = repvar;
7244  negated = FALSE;
7245  }
7246 
7247  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7248  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7249  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7250  *
7251  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7252  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7253  *
7254  * The explanation for the following block:
7255  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7256  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7257  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7258  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7259  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7260  * 2) For all replacement variable we check:
7261  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7262  * capacity -= weight * a_i caused by the negation of y_i.
7263  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7264  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7265  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7266  * weight in this case.
7267  */
7268  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7269  {
7270  SCIP_VAR** aggrvars;
7271  SCIP_Real* aggrscalars;
7272  SCIP_Real aggrconst;
7273  int naggrvars;
7274  int i;
7275 
7276  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7277  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7278  aggrvars = SCIPvarGetMultaggrVars(workvar);
7279  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7280  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7281  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7282 
7283  if( !SCIPisIntegral(scip, weight * aggrconst) )
7284  {
7285  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7286  return SCIP_ERROR;
7287  }
7288 
7289  /* if workvar was negated, we have to flip the weight */
7290  if( negated )
7291  weight *= -1;
7292 
7293  for( i = naggrvars - 1; i >= 0; --i )
7294  {
7295  assert(aggrvars != NULL);
7296  assert(aggrscalars != NULL);
7297 
7298  if( !SCIPvarIsBinary(aggrvars[i]) )
7299  {
7300  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7301  SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7302  return SCIP_ERROR;
7303  }
7304  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7305  {
7306  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7307  return SCIP_ERROR;
7308  }
7309  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7310  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7311  {
7312  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7313  assert(negvar != NULL);
7314  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7315  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7316  }
7317  else
7318  {
7319  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7320  }
7321  }
7322  /* delete old coefficient */
7323  SCIP_CALL( delCoefPos(scip, cons, v) );
7324 
7325  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7326  if( negated )
7327  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7328  else
7329  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7330 
7331  if( consdata->capacity < 0 )
7332  {
7333  if( cutoff != NULL )
7334  {
7335  *cutoff = TRUE;
7336  break;
7337  }
7338  }
7339  }
7340  /* check, if the variable should be replaced with the representative */
7341  else if( repvar != var )
7342  {
7343  /* delete old (aggregated) variable */
7344  SCIP_CALL( delCoefPos(scip, cons, v) );
7345 
7346  /* add representative instead */
7347  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7348  }
7349  else
7350  ++v;
7351  }
7352  }
7353  assert(consdata->onesweightsum == 0);
7354 
7355  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7356  SCIPdebugPrintCons(scip, cons, NULL);
7357 
7358  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7359  * clean up the constraint
7360  */
7361  if( cutoff != NULL && !(*cutoff) )
7362  {
7363  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7364  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7365  SCIPdebugPrintCons(scip, cons, NULL);
7366  }
7367 
7368  return SCIP_OKAY;
7369 }
7370 
7371 
7372 /** propagation method for knapsack constraints */
7373 static
7375  SCIP* scip, /**< SCIP data structure */
7376  SCIP_CONS* cons, /**< knapsack constraint */
7377  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7378  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7379  int* nfixedvars, /**< pointer to count number of fixings */
7380  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7381  )
7383  SCIP_CONSDATA* consdata;
7384  SCIP_Bool infeasible;
7385  SCIP_Bool tightened;
7386  SCIP_Longint* secondmaxweights;
7387  SCIP_Longint minweightsum;
7388  SCIP_Longint residualcapacity;
7389 
7390  int nvars;
7391  int i;
7392  int nnegcliques;
7393 
7394  SCIP_VAR** myvars;
7395  SCIP_Longint* myweights;
7396  int* cliquestartposs;
7397  int* cliqueendposs;
7398  SCIP_Longint localminweightsum;
7399  SCIP_Bool foundmax;
7400  int c;
7401 
7402  assert(scip != NULL);
7403  assert(cons != NULL);
7404  assert(cutoff != NULL);
7405  assert(redundant != NULL);
7406  assert(nfixedvars != NULL);
7407 
7408  consdata = SCIPconsGetData(cons);
7409  assert(consdata != NULL);
7410 
7411  *cutoff = FALSE;
7412  *redundant = FALSE;
7413 
7414  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7415 
7416  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7417  if( !SCIPinRepropagation(scip) )
7418  {
7419  SCIP_CALL( SCIPincConsAge(scip, cons) );
7420  }
7421 
7422 #ifndef NDEBUG
7423  /* assert that only active or negated variables are present */
7424  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7425  {
7426  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7427  }
7428 #endif
7429 
7430  usenegatedclique = usenegatedclique && consdata->merged;
7431 
7432  /* init for debugging */
7433  myvars = NULL;
7434  myweights = NULL;
7435  cliquestartposs = NULL;
7436  secondmaxweights = NULL;
7437  minweightsum = 0;
7438  nvars = consdata->nvars;
7439  /* make sure, the items are sorted by non-increasing weight */
7440  sortItems(consdata);
7441 
7442  do
7443  {
7444  localminweightsum = 0;
7445 
7446  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7447  * a negated clique means, that at most one of the clique variables can be zero
7448  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7449  *
7450  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7451  * since replacing i with the element of maximal weight leads to infeasibility
7452  */
7453  if( usenegatedclique && nvars > 0 )
7454  {
7455  SCIP_CONSHDLRDATA* conshdlrdata;
7456  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7457  assert(conshdlrdata != NULL);
7458 
7459  /* compute clique partitions */
7460  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7461  nnegcliques = consdata->nnegcliques;
7462 
7463  /* if we have no real negated cliques we can stop here */
7464  if( nnegcliques == nvars )
7465  {
7466  /* run the standard algorithm that does not involve cliques */
7467  usenegatedclique = FALSE;
7468  break;
7469  }
7470 
7471  /* allocate temporary memory and initialize it */
7472  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7473  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7474  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7475  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7476  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7477  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7478 
7479  /* resort variables to avoid quadratic algorithm later on */
7480  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7481 
7482  /* save the end positions of the cliques because start positions are moved in the following loop */
7483  for( c = 0; c < nnegcliques; ++c )
7484  {
7485  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7486  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7487  }
7488 
7489  c = 0;
7490  foundmax = FALSE;
7491  i = 0;
7492 
7493  while( i < nvars )
7494  {
7495  /* ignore variables of the negated clique which are fixed to one since these are counted in
7496  * consdata->onesweightsum
7497  */
7498 
7499  /* if there are only one variable negated cliques left we can stop */
7500  if( nnegcliques - c == nvars - i )
7501  {
7502  minweightsum += localminweightsum;
7503  localminweightsum = 0;
7504  break;
7505  }
7506 
7507  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7508  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7509  * other clique variables to one
7510  */
7511  if( cliquestartposs[c] == i )
7512  {
7513  assert(myweights[i] > 0);
7514  ++c;
7515  minweightsum += localminweightsum;
7516  localminweightsum = 0;
7517  foundmax = TRUE;
7518 
7519  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7520  foundmax = FALSE;
7521 
7522  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7523  {
7524  ++i;
7525  continue;
7526  }
7527  }
7528 
7529  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7530  {
7531  assert(myweights[i] > 0);
7532 
7533  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7534  {
7535  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7536 
7537  if( !foundmax )
7538  {
7539  foundmax = TRUE;
7540 
7541  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7542  cliquestartposs[c - 1] = i;
7543  ++i;
7544 
7545  continue;
7546  }
7547  /* memorize second max weight for each clique */
7548  if( secondmaxweights[c - 1] == 0 )
7549  secondmaxweights[c - 1] = myweights[i];
7550 
7551  localminweightsum += myweights[i];
7552  }
7553  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7554  else
7555  {
7556  int v;
7557  /* fix all other variables of the negated clique to 1 */
7558  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7559  {
7560  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7561  {
7562  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7563  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7564 
7565  if( infeasible )
7566  {
7567  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7568 
7569  /* analyze the infeasibility if conflict analysis is applicable */
7571  {
7572  /* conflict analysis can only be applied in solving stage */
7573  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7574 
7575  /* initialize the conflict analysis */
7577 
7578  /* add the two variables which are fixed to zero within a negated clique */
7579  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7580  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7581 
7582  /* start the conflict analysis */
7583  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7584  }
7585  *cutoff = TRUE;
7586  break;
7587  }
7588  assert(tightened);
7589  ++(*nfixedvars);
7590  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7591  }
7592  }
7593 
7594  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7595  localminweightsum = 0;
7596  /* we can jump to the end of this clique */
7597  i = cliqueendposs[c - 1];
7598 
7599  if( *cutoff )
7600  break;
7601  }
7602  }
7603  ++i;
7604  }
7605  /* add last clique minweightsum */
7606  minweightsum += localminweightsum;
7607 
7608  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7609  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7610 
7611  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7612  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7613  {
7614  SCIP_Longint maxcliqueweight = -1LL;
7615 
7616  /* loop over cliques */
7617  for( c = 0; c < nnegcliques; ++c )
7618  {
7619  SCIP_VAR* maxvar;
7620  SCIP_Bool maxvarfixed;
7621  int endvarposclique;
7622  int startvarposclique;
7623 
7624  assert(myvars != NULL);
7625  assert(nnegcliques == consdata->nnegcliques);
7626  assert(myweights != NULL);
7627  assert(secondmaxweights != NULL);
7628  assert(cliquestartposs != NULL);
7629 
7630  endvarposclique = cliqueendposs[c];
7631  startvarposclique = cliquestartposs[c];
7632 
7633  maxvar = myvars[startvarposclique];
7634 
7635  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7636  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7637  continue;
7638 
7639  maxcliqueweight = myweights[startvarposclique];
7640  maxvarfixed = FALSE;
7641  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7642  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7643  * exceeds the capacity the maximum weight variable can be fixed to zero.
7644  */
7645  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7646  {
7647 #ifndef NDEBUG
7648  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7649 #endif
7650  assert(maxcliqueweight >= secondmaxweights[c]);
7651  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7652 
7653  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7654  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7655  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7656  assert(consdata->onesweightsum == oldonesweightsum);
7657  assert(!infeasible);
7658  assert(tightened);
7659  (*nfixedvars)++;
7660  maxvarfixed = TRUE;
7661  }
7662  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7663  * fits into the knapsack
7664  */
7665  else if( nnegcliques - c == nvars - startvarposclique )
7666  break;
7667  /* early termination of the remaining loop because no further variable fixings are possible:
7668  *
7669  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7670  * largest was set to 0) does not suffice to infer additional variable fixings because
7671  *
7672  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7673  * - their second largest elements are at least as large as the smallest weight of the knapsack
7674  */
7675  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7676  break;
7677 
7678  /* loop over items with non-maximal weight (omitting the first position) */
7679  for( i = endvarposclique; i > startvarposclique; --i )
7680  {
7681  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7682  * messed up the clique preprocessing in the previous loop to filter those variables out */
7683  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7684 
7685  /* only check variables of negated cliques for which no variable is locally fixed */
7686  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7687  {
7688  assert(maxcliqueweight >= myweights[i]);
7689  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7690 
7691  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7692  *
7693  * the maxvar was already fixed to 0 because it has a huge gain.
7694  *
7695  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7696  * since replacing i with the element of maximal weight leads to infeasibility */
7697  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7698  {
7699 #ifndef NDEBUG
7700  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7701 #endif
7702  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7703  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7704  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7705  assert(!infeasible);
7706  assert(tightened);
7707  ++(*nfixedvars);
7708  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7709 
7710  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7711  * consdata->onesweightsum
7712  */
7713  minweightsum -= myweights[i];
7714  assert(minweightsum >= 0);
7715  }
7716  else
7717  break;
7718  }
7719  }
7720 #ifndef NDEBUG
7721  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7722  for( ; i > startvarposclique; --i )
7723  {
7724  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7725  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7726 
7727  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7728  assert(varisfixed || !exceedscapacity);
7729  }
7730 #endif
7731  }
7732  }
7733  SCIPfreeBufferArray(scip, &secondmaxweights);
7734  SCIPfreeBufferArray(scip, &cliqueendposs);
7735  SCIPfreeBufferArray(scip, &cliquestartposs);
7736  SCIPfreeBufferArray(scip, &myweights);
7737  SCIPfreeBufferArray(scip, &myvars);
7738  }
7739 
7740  assert(consdata->negcliquepartitioned || minweightsum == 0);
7741  }
7742  while( FALSE );
7743 
7744  assert(usenegatedclique || minweightsum == 0);
7745  /* check, if weights of fixed variables already exceed knapsack capacity */
7746  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7747  {
7748  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7749  consdata->onesweightsum, consdata->capacity);
7750 
7751  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7752  *cutoff = TRUE;
7753 
7754  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7756  {
7757  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7758  SCIP_Longint weight;
7759 
7760  weight = 0;
7761 
7763 
7764  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7765  {
7766  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7767  {
7768  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7769  weight += consdata->weights[i];
7770  }
7771  }
7772 
7773  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7774  }
7775 
7776  return SCIP_OKAY;
7777  }
7778 
7779  /* the algorithm below is a special case of propagation involving negated cliques */
7780  if( !usenegatedclique )
7781  {
7782  assert(consdata->sorted);
7783  residualcapacity = consdata->capacity - consdata->onesweightsum;
7784 
7785  /* fix all variables to zero, that don't fit into the knapsack anymore */
7786  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7787  {
7788  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7789  * to zero
7790  */
7791  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7792  {
7793  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7794  {
7795  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7796  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7797  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7798  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7799  assert(!infeasible);
7800  assert(tightened);
7801  (*nfixedvars)++;
7802  }
7803  }
7804  }
7805  }
7806 
7807  /* check if the knapsack is now redundant */
7808  if( !SCIPconsIsModifiable(cons) )
7809  {
7810  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7811 
7812  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7813  for( i = 0; i < nvars; ++i )
7814  {
7815  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7816  {
7817  unfixedweightsum += consdata->weights[i];
7818 
7819  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7820  if( unfixedweightsum > consdata->capacity )
7821  return SCIP_OKAY;
7822  }
7823  }
7824  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7825  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7826  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7827  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7828  *redundant = TRUE;
7829  }
7830 
7831  return SCIP_OKAY;
7832 }
7833 
7834 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7835  * containing all negated variables of this knapsack constraint
7836  */
7837 static
7839  SCIP* scip, /**< SCIP data structure */
7840  SCIP_CONS* cons, /**< knapsack constraint */
7841  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7842  int* naddconss /**< pointer to count number of added constraints */
7843  )
7844 {
7845  SCIP_CONS* newcons;
7846  SCIP_CONSDATA* consdata;
7847 
7848  assert(scip != NULL);
7849  assert(cons != NULL);
7850  assert(ndelconss != NULL);
7851  assert(naddconss != NULL);
7852 
7853  consdata = SCIPconsGetData(cons);
7854  assert(consdata != NULL);
7855  assert(consdata->nvars > 1);
7856 
7857  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7858  if( consdata->nvars == 2 )
7859  {
7860  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7861 
7862  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7866  SCIPconsIsStickingAtNode(cons)) );
7867  }
7868  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7869  * containing all negated variables of the knapsack
7870  */
7871  else
7872  {
7873  SCIP_VAR** consvars;
7874 
7875  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7876 
7877  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7878  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7879 
7880  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7884  SCIPconsIsStickingAtNode(cons)) );
7885 
7886  SCIPfreeBufferArray(scip, &consvars);
7887  }
7888 
7889  SCIP_CALL( SCIPaddCons(scip, newcons) );
7890  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7891  ++(*naddconss);
7892 
7893  SCIP_CALL( SCIPdelCons(scip, cons) );
7894  ++(*ndelconss);
7895 
7896  return SCIP_OKAY;
7897 }
7898 
7899 /** delete redundant variables
7900  *
7901  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7902  *
7903  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7904  * => x4, x5 always fits into the knapsack, so we can delete them
7905  *
7906  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7907  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7908  */
7909 static
7911  SCIP* scip, /**< SCIP data structure */
7912  SCIP_CONS* cons, /**< knapsack constraint */
7913  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7914  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7915  * first which did not fit */
7916  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7917  int* nchgsides, /**< pointer to store the amount of changed sides */
7918  int* naddconss /**< pointer to count number of added constraints */
7919  )
7920 {
7921  SCIP_CONSHDLRDATA* conshdlrdata;
7922  SCIP_CONSDATA* consdata;
7923  SCIP_VAR** vars;
7924  SCIP_Longint* weights;
7925  SCIP_Longint capacity;
7926  SCIP_Longint gcd;
7927  int nvars;
7928  int w;
7929 
7930  assert(scip != NULL);
7931  assert(cons != NULL);
7932  assert(nchgcoefs != NULL);
7933  assert(nchgsides != NULL);
7934  assert(naddconss != NULL);
7935 
7936  consdata = SCIPconsGetData(cons);
7937  assert(consdata != NULL);
7938  assert(0 < frontsum && frontsum < consdata->weightsum);
7939  assert(0 < splitpos && splitpos < consdata->nvars);
7940 
7941  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7942  assert(conshdlrdata != NULL);
7943 
7944  vars = consdata->vars;
7945  weights = consdata->weights;
7946  nvars = consdata->nvars;
7947  capacity = consdata->capacity;
7948 
7949  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7950  * weight must not be sorted by their index
7951  */
7952 #ifndef NDEBUG
7953  for( w = nvars - 1; w > 0; --w )
7954  assert(weights[w] <= weights[w-1]);
7955 #endif
7956 
7957  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7958  if( consdata->nvars - 1 == splitpos )
7959  return SCIP_OKAY;
7960 
7961  assert(frontsum + weights[splitpos] > capacity);
7962 
7963  /* detect redundant variables */
7964  if( consdata->weightsum - weights[splitpos] <= capacity )
7965  {
7966  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7967  * fit
7968  */
7969  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7970 
7971  /* delete items and update capacity */
7972  for( w = nvars - 1; w > splitpos; --w )
7973  {
7974  consdata->capacity -= weights[w];
7975  SCIP_CALL( delCoefPos(scip, cons, w) );
7976  }
7977  assert(w == splitpos);
7978 
7979  ++(*nchgsides);
7980  *nchgcoefs += (nvars - splitpos);
7981 
7982  /* division by greatest common divisor */
7983  gcd = weights[w];
7984  for( ; w >= 0 && gcd > 1; --w )
7985  {
7986  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7987  }
7988 
7989  /* normalize if possible */
7990  if( gcd > 1 )
7991  {
7992  for( w = splitpos; w >= 0; --w )
7993  {
7994  consdataChgWeight(consdata, w, weights[w]/gcd);
7995  }
7996  (*nchgcoefs) += nvars;
7997 
7998  consdata->capacity /= gcd;
7999  ++(*nchgsides);
8000  }
8001 
8002  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8003  * weight must not be sorted by their index
8004  */
8005 #ifndef NDEBUG
8006  for( w = consdata->nvars - 1; w > 0; --w )
8007  assert(weights[w] <= weights[w - 1]);
8008 #endif
8009  }
8010  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8011  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8012  * splitpos and needs to fit into the knapsack
8013  */
8014  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8015  {
8016  int* clqpart;
8017  int nclq;
8018  int len;
8019 
8020  len = nvars - (splitpos + 1);
8021  /* allocate temporary memory */
8022  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8023 
8024  /* calculate clique partition */
8025  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8026 
8027  /* check if we found at least one clique */
8028  if( nclq < len )
8029  {
8030  SCIP_Longint maxactduetoclq;
8031  int cliquenum;
8032 
8033  maxactduetoclq = 0;
8034  cliquenum = 0;
8035 
8036  /* calculate maximum activity due to cliques */
8037  for( w = 0; w < len; ++w )
8038  {
8039  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8040  if( clqpart[w] == cliquenum )
8041  {
8042  maxactduetoclq += weights[w + splitpos + 1];
8043  ++cliquenum;
8044  }
8045  }
8046 
8047  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8048  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8049  */
8050  if( frontsum + maxactduetoclq <= capacity )
8051  {
8052  SCIP_VAR** clqvars;
8053  int nclqvars;
8054  int c;
8055 
8056  assert(maxactduetoclq < weights[splitpos]);
8057 
8058  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8059 
8060  /* allocate temporary memory */
8061  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8062 
8063  for( c = 0; c < nclq; ++c )
8064  {
8065  nclqvars = 0;
8066  for( w = 0; w < len; ++w )
8067  {
8068  if( clqpart[w] == c )
8069  {
8070  clqvars[nclqvars] = vars[w + splitpos + 1];
8071  ++nclqvars;
8072  }
8073  }
8074 
8075  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8076  if( nclqvars > 1 )
8077  {
8078  SCIP_CONS* cliquecons;
8079  char name[SCIP_MAXSTRLEN];
8080 
8081  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8082  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8086  SCIPconsIsStickingAtNode(cons)) );
8087  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8088  SCIPdebugPrintCons(scip, cliquecons, NULL);
8089  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8090  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8091  ++(*naddconss);
8092  }
8093  }
8094 
8095  /* delete items and update capacity */
8096  for( w = nvars - 1; w > splitpos; --w )
8097  {
8098  SCIP_CALL( delCoefPos(scip, cons, w) );
8099  ++(*nchgcoefs);
8100  }
8101  consdata->capacity -= maxactduetoclq;
8102  assert(frontsum <= consdata->capacity);
8103  ++(*nchgsides);
8104 
8105  assert(w == splitpos);
8106 
8107  /* renew weights pointer */
8108  weights = consdata->weights;
8109 
8110  /* division by greatest common divisor */
8111  gcd = weights[w];
8112  for( ; w >= 0 && gcd > 1; --w )
8113  {
8114  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8115  }
8116 
8117  /* normalize if possible */
8118  if( gcd > 1 )
8119  {
8120  for( w = splitpos; w >= 0; --w )
8121  {
8122  consdataChgWeight(consdata, w, weights[w]/gcd);
8123  }
8124  (*nchgcoefs) += nvars;
8125 
8126  consdata->capacity /= gcd;
8127  ++(*nchgsides);
8128  }
8129 
8130  /* free temporary memory */
8131  SCIPfreeBufferArray(scip, &clqvars);
8132 
8133  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8134  * weight must not be sorted by their index
8135  */
8136 #ifndef NDEBUG
8137  for( w = consdata->nvars - 1; w > 0; --w )
8138  assert(weights[w] <= weights[w - 1]);
8139 #endif
8140  }
8141  }
8142 
8143  /* free temporary memory */
8144  SCIPfreeBufferArray(scip, &clqpart);
8145  }
8146 
8147  return SCIP_OKAY;
8148 }
8149 
8150 /* detect redundant variables which always fits into the knapsack
8151  *
8152  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8153  *
8154  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8155  * => x4, x5 always fits into the knapsack, so we can delete them
8156  *
8157  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8158  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8159  */
8160 static
8162  SCIP* scip, /**< SCIP data structure */
8163  SCIP_CONS* cons, /**< knapsack constraint */
8164  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8165  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8166  int* nchgsides, /**< pointer to store the amount of changed sides */
8167  int* naddconss /**< pointer to count number of added constraints */
8168  )
8170  SCIP_CONSHDLRDATA* conshdlrdata;
8171  SCIP_CONSDATA* consdata;
8172  SCIP_VAR** vars;
8173  SCIP_Longint* weights;
8174  SCIP_Longint capacity;
8175  SCIP_Longint sum;
8176  int noldchgcoefs;
8177  int nvars;
8178  int v;
8179  int w;
8180 
8181  assert(scip != NULL);
8182  assert(cons != NULL);
8183  assert(ndelconss != NULL);
8184  assert(nchgcoefs != NULL);
8185  assert(nchgsides != NULL);
8186  assert(naddconss != NULL);
8187 
8188  consdata = SCIPconsGetData(cons);
8189  assert(consdata != NULL);
8190  assert(consdata->nvars >= 2);
8191  assert(consdata->weightsum > consdata->capacity);
8192 
8193  noldchgcoefs = *nchgcoefs;
8194  vars = consdata->vars;
8195  weights = consdata->weights;
8196  nvars = consdata->nvars;
8197  capacity = consdata->capacity;
8198  sum = 0;
8199 
8200  /* search for maximal fitting items */
8201  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8202  sum += weights[v];
8203 
8204  assert(v < nvars);
8205 
8206  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8207  if( v == nvars - 1 )
8208  {
8209  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8210  assert(SCIPconsIsDeleted(cons));
8211 
8212  return SCIP_OKAY;
8213  }
8214 
8215  if( v < nvars - 1 )
8216  {
8217  /* try to delete variables */
8218  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8219  assert(consdata->nvars > 1);
8220 
8221  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8222  if( v == consdata->nvars - 1 )
8223  {
8224  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8225  assert(SCIPconsIsDeleted(cons));
8226  }
8227 
8228  return SCIP_OKAY;
8229  }
8230 
8231  /* if we already found some redundant variables, stop here */
8232  if( *nchgcoefs > noldchgcoefs )
8233  return SCIP_OKAY;
8234 
8235  assert(vars == consdata->vars);
8236  assert(weights == consdata->weights);
8237  assert(nvars == consdata->nvars);
8238  assert(capacity == consdata->capacity);
8239 
8240  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8241  assert(conshdlrdata != NULL);
8242  /* calculate clique partition */
8243  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8244 
8245  /* check for real existing cliques */
8246  if( consdata->cliquepartition[v] < v )
8247  {
8248  SCIP_Longint sumfront;
8249  SCIP_Longint maxactduetoclqfront;
8250  int* clqpart;
8251  int cliquenum;
8252 
8253  sumfront = 0;
8254  maxactduetoclqfront = 0;
8255 
8256  clqpart = consdata->cliquepartition;
8257  cliquenum = 0;
8258 
8259  /* calculate maximal activity due to cliques */
8260  for( w = 0; w < nvars; ++w )
8261  {
8262  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8263  if( clqpart[w] == cliquenum )
8264  {
8265  if( maxactduetoclqfront + weights[w] <= capacity )
8266  {
8267  maxactduetoclqfront += weights[w];
8268  ++cliquenum;
8269  }
8270  else
8271  break;
8272  }
8273  sumfront += weights[w];
8274  }
8275  assert(w >= v);
8276 
8277  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8278  * information
8279  */
8280  if( conshdlrdata->disaggregation && w == nvars )
8281  {
8282  SCIP_VAR** clqvars;
8283  int nclqvars;
8284  int c;
8285  int ncliques;
8286 
8287  assert(maxactduetoclqfront <= capacity);
8288 
8289  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8290 
8291  ncliques = consdata->ncliques;
8292 
8293  /* allocate temporary memory */
8294  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8295 
8296  for( c = 0; c < ncliques; ++c )
8297  {
8298  nclqvars = 0;
8299  for( w = 0; w < nvars; ++w )
8300  {
8301  if( clqpart[w] == c )
8302  {
8303  clqvars[nclqvars] = vars[w];
8304  ++nclqvars;
8305  }
8306  }
8307 
8308  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8309  if( nclqvars > 1 )
8310  {
8311  SCIP_CONS* cliquecons;
8312  char name[SCIP_MAXSTRLEN];
8313 
8314  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8315  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8319  SCIPconsIsStickingAtNode(cons)) );
8320  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8321  SCIPdebugPrintCons(scip, cliquecons, NULL);
8322  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8323  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8324  ++(*naddconss);
8325  }
8326  }
8327 
8328  /* delete old constraint */
8329  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8330  ++(*ndelconss);
8331 
8332  SCIPfreeBufferArray(scip, &clqvars);
8333 
8334  return SCIP_OKAY;
8335  }
8336 
8337  if( w > v && w < nvars - 1 )
8338  {
8339  /* try to delete variables */
8340  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8341  }
8342  }
8343 
8344  return SCIP_OKAY;
8345 }
8346 
8347 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8348 static
8349 void normalizeWeights(
8350  SCIP_CONS* cons, /**< knapsack constraint */
8351  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8352  int* nchgsides /**< pointer to count number of side changes */
8353  )
8354 {
8355  SCIP_CONSDATA* consdata;
8356  SCIP_Longint gcd;
8357  int i;
8358 
8359  assert(nchgcoefs != NULL);
8360  assert(nchgsides != NULL);
8361  assert(!SCIPconsIsModifiable(cons));
8362 
8363  consdata = SCIPconsGetData(cons);
8364  assert(consdata != NULL);
8365  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8366  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8367  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8368  assert(consdata->nvars >= 1);
8369 
8370  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8371  sortItems(consdata);
8372 
8373  gcd = consdata->weights[consdata->nvars-1];
8374  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8375  {
8376  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8377  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8378 
8379  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8380  }
8381 
8382  if( gcd >= 2 )
8383  {
8384  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8385 
8386  for( i = 0; i < consdata->nvars; ++i )
8387  {
8388  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8389  }
8390  consdata->capacity /= gcd;
8391  (*nchgcoefs) += consdata->nvars;
8392  (*nchgsides)++;
8393 
8394  /* weight should still be sorted, because the reduction preserves this */
8395 #ifndef NDEBUG
8396  for( i = consdata->nvars - 1; i > 0; --i )
8397  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8398 #endif
8399  consdata->sorted = TRUE;
8400  }
8401 }
8402 
8403 /** dual weights tightening for knapsack constraints
8404  *
8405  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8406  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8407  * constraint
8408  *
8409  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8410  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8411  *
8412  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8413  *
8414  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8415  *
8416  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8417  *
8418  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8419  *
8420  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8421  */
8422 static
8424  SCIP* scip, /**< SCIP data structure */
8425  SCIP_CONS* cons, /**< knapsack constraint */
8426  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8427  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8428  int* nchgsides, /**< pointer to store the amount of changed sides */
8429  int* naddconss /**< pointer to count number of added constraints */
8430  )
8432  SCIP_CONSDATA* consdata;
8433  SCIP_Longint* weights;
8434  SCIP_Longint dualcapacity;
8435  SCIP_Longint reductionsum;
8436  SCIP_Longint capacity;
8437  SCIP_Longint exceedsum;
8438  int oldnchgcoefs;
8439  int nvars;
8440  int vbig;
8441  int v;
8442  int w;
8443 #ifndef NDEBUG
8444  int oldnchgsides;
8445 #endif
8446 
8447  assert(scip != NULL);
8448  assert(cons != NULL);
8449  assert(ndelconss != NULL);
8450  assert(nchgcoefs != NULL);
8451  assert(nchgsides != NULL);
8452  assert(naddconss != NULL);
8453 
8454 #ifndef NDEBUG
8455  oldnchgsides = *nchgsides;
8456 #endif
8457 
8458  consdata = SCIPconsGetData(cons);
8459  assert(consdata != NULL);
8460  assert(consdata->weightsum > consdata->capacity);
8461  assert(consdata->nvars >= 2);
8462  assert(consdata->sorted);
8463 
8464  /* constraint should be merged */
8465  assert(consdata->merged);
8466 
8467  nvars = consdata->nvars;
8468  weights = consdata->weights;
8469  capacity = consdata->capacity;
8470 
8471  oldnchgcoefs = *nchgcoefs;
8472 
8473  /* case 1. */
8474  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8475  {
8476  SCIP_CONS* newcons;
8477 
8478  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8479  *
8480  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8481  */
8482  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8483 
8484  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8488  SCIPconsIsStickingAtNode(cons)) );
8489 
8490  SCIP_CALL( SCIPaddCons(scip, newcons) );
8491  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8492  ++(*naddconss);
8493 
8494  SCIP_CALL( SCIPdelCons(scip, cons) );
8495  ++(*ndelconss);
8496 
8497  return SCIP_OKAY;
8498  }
8499 
8500  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8501  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8502  {
8503  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8504  assert(SCIPconsIsDeleted(cons));
8505 
8506  return SCIP_OKAY;
8507  }
8508 
8509  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8510  /* @todo might be changed/removed when improving the coeffcients tightening */
8511  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8512  return SCIP_OKAY;
8513 
8514  /* case 2. */
8515 
8516  v = 0;
8517 
8518  /* @todo generalize the following algorithm for several parts of the knapsack
8519  *
8520  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8521  * variables each combination is a minimal cover, some examples
8522  *
8523  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8524  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8525  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8526  *
8527  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8528  *
8529  */
8530 
8531  /* determine big weights that fit only by itself */
8532  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8533  ++v;
8534 
8535  vbig = v;
8536  assert(vbig < nvars - 1);
8537  exceedsum = 0;
8538 
8539  /* determine the amount needed to exceed the capacity */
8540  while( v < nvars && exceedsum <= capacity )
8541  {
8542  exceedsum += weights[v];
8543  ++v;
8544  }
8545 
8546  /* if we exceeded the capacity we might reduce the weights */
8547  if( exceedsum > capacity )
8548  {
8549  assert(vbig > 0 || v < nvars);
8550 
8551  /* all small weights were needed to exceed the capacity */
8552  if( v == nvars )
8553  {
8554  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8555  assert(newweight > 0);
8556 
8557  /* reduce big weights */
8558  for( v = 0; v < vbig; ++v )
8559  {
8560  if( weights[v] > newweight )
8561  {
8562  consdataChgWeight(consdata, v, newweight);
8563  ++(*nchgcoefs);
8564  }
8565  }
8566 
8567  /* reduce small weights */
8568  for( ; v < nvars; ++v )
8569  {
8570  if( weights[v] > 1 )
8571  {
8572  consdataChgWeight(consdata, v, 1LL);
8573  ++(*nchgcoefs);
8574  }
8575  }
8576 
8577  consdata->capacity = newweight;
8578 
8579  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8580  * weight must not be sorted by their index
8581  */
8582 #ifndef NDEBUG
8583  for( v = nvars - 1; v > 0; --v )
8584  assert(weights[v] <= weights[v-1]);
8585 #endif
8586 
8587  return SCIP_OKAY;
8588  }
8589  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8590  * small weights
8591  */
8592  else
8593  {
8594  SCIP_Longint exceedsumback = 0;
8595  int nexceed = v - vbig;
8596 
8597  assert(nexceed > 1);
8598 
8599  /* determine weightsum of the same amount as before but of the smallest weight */
8600  for( w = nvars - 1; w >= nvars - nexceed; --w )
8601  exceedsumback += weights[w];
8602 
8603  assert(w >= 0);
8604 
8605  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8606  * combinations of all small weights
8607  */
8608  if( exceedsumback > capacity )
8609  {
8610  SCIP_Longint newweight = nexceed - 1;
8611 
8612  /* taking out the smallest element needs to fit */
8613  assert(exceedsumback - weights[nvars - 1] <= capacity);
8614 
8615  /* reduce big weights */
8616  for( v = 0; v < vbig; ++v )
8617  {
8618  if( weights[v] > newweight )
8619  {
8620  consdataChgWeight(consdata, v, newweight);
8621  ++(*nchgcoefs);
8622  }
8623  }
8624 
8625  /* reduce small weights */
8626  for( ; v < nvars; ++v )
8627  {
8628  if( weights[v] > 1 )
8629  {
8630  consdataChgWeight(consdata, v, 1LL);
8631  ++(*nchgcoefs);
8632  }
8633  }
8634 
8635  consdata->capacity = newweight;
8636 
8637  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8638  * weight must not be sorted by their index
8639  */
8640 #ifndef NDEBUG
8641  for( v = nvars - 1; v > 0; --v )
8642  assert(weights[v] <= weights[v-1]);
8643 #endif
8644  return SCIP_OKAY;
8645  }
8646  }
8647  }
8648  else
8649  {
8650  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8651  * not happen here
8652  */
8653  assert(vbig > 0 && vbig < nvars);
8654 
8655  /* either choose a big coefficients or all other variables
8656  *
8657  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8658  *
8659  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8660  * constraint to
8661  *
8662  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8663  */
8664 
8665  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8666  {
8667  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8668 #ifndef NDEBUG
8669  SCIP_Longint resweightsum = consdata->weightsum;
8670 
8671  for( v = 0; v < vbig; ++v )
8672  resweightsum -= weights[v];
8673 
8674  assert(exceedsum == resweightsum);
8675 #endif
8676  assert(newweight > 0);
8677 
8678  /* reduce big weights */
8679  for( v = 0; v < vbig; ++v )
8680  {
8681  if( weights[v] > newweight )
8682  {
8683  consdataChgWeight(consdata, v, newweight);
8684  ++(*nchgcoefs);
8685  }
8686  }
8687 
8688  /* reduce small weights */
8689  for( ; v < nvars; ++v )
8690  {
8691  if( weights[v] > 1 )
8692  {
8693  consdataChgWeight(consdata, v, 1LL);
8694  ++(*nchgcoefs);
8695  }
8696  }
8697 
8698  consdata->capacity = newweight;
8699 
8700  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8701  * weight must not be sorted by their index
8702  */
8703 #ifndef NDEBUG
8704  for( v = nvars - 1; v > 0; --v )
8705  assert(weights[v] <= weights[v-1]);
8706 #endif
8707  return SCIP_OKAY;
8708  }
8709  }
8710 
8711  /* case 3. */
8712 
8713  dualcapacity = consdata->weightsum - capacity;
8714  reductionsum = 0;
8715  v = 0;
8716 
8717  /* reduce big weights
8718  *
8719  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8720  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8721  * <=> x0 + x1 + x2 + x3 <= 3
8722  */
8723  while( weights[v] > dualcapacity )
8724  {
8725  reductionsum += (weights[v] - dualcapacity);
8726  consdataChgWeight(consdata, v, dualcapacity);
8727  ++v;
8728  assert(v < nvars);
8729  }
8730  (*nchgcoefs) += v;
8731 
8732  /* skip weights equal to the dualcapacity, because we cannot change them */
8733  while( v < nvars && weights[v] == dualcapacity )
8734  ++v;
8735 
8736  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8737  * after a possible removal of the last, redundant item
8738  *
8739  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8740  */
8741  if( v >= nvars - 1 )
8742  {
8743  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8744  if( v == nvars - 1 )
8745  {
8746  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8747  }
8748  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8749  assert(SCIPconsIsDeleted(cons));
8750 
8751  return SCIP_OKAY;
8752  }
8753  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8754  {
8755  /* @todo generalize the following algorithm for more than two variables */
8756 
8757  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8758  {
8759  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8760  * coefficients) of all or two variables of the rest
8761  *
8762  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8763  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8764  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8765  *
8766  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8767  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8768  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8769  *
8770  */
8771  if( v > 0 && weights[nvars - 2] > 1 )
8772  {
8773  int ncoefchg = 0;
8774 
8775  /* reduce all bigger weights */
8776  for( w = 0; w < v; ++w )
8777  {
8778  if( weights[w] > 2 )
8779  {
8780  consdataChgWeight(consdata, w, 2LL);
8781  ++ncoefchg;
8782  }
8783  else
8784  {
8785  assert(weights[0] == 2);
8786  assert(weights[v - 1] == 2);
8787  break;
8788  }
8789  }
8790 
8791  /* reduce all smaller weights */
8792  for( w = v; w < nvars; ++w )
8793  {
8794  if( weights[w] > 1 )
8795  {
8796  consdataChgWeight(consdata, w, 1LL);
8797  ++ncoefchg;
8798  }
8799  }
8800  assert(ncoefchg > 0);
8801 
8802  (*nchgcoefs) += ncoefchg;
8803 
8804  /* correct the capacity */
8805  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8806  assert(consdata->capacity > 0);
8807  assert(weights[0] <= consdata->capacity);
8808  assert(consdata->weightsum > consdata->capacity);
8809  /* reset the reductionsum */
8810  reductionsum = 0;
8811  }
8812  else if( v == 0 )
8813  {
8814  assert(weights[nvars - 2] == 1);
8815  }
8816  }
8817  else
8818  {
8819  SCIP_Longint minweight = weights[nvars - 1];
8820  SCIP_Longint newweight = dualcapacity - minweight;
8821  SCIP_Longint restsumweights = 0;
8822  SCIP_Longint sumcoef;
8823  SCIP_Bool sumcoefcase = FALSE;
8824  int startv = v;
8825  int end;
8826  int k;
8827 
8828  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8829 
8830  /* reduce big weights of pairs that exceed the dualcapacity
8831  *
8832  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8833  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8834  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8835  */
8836  while( weights[v] > newweight )
8837  {
8838  reductionsum += (weights[v] - newweight);
8839  consdataChgWeight(consdata, v, newweight);
8840  ++v;
8841  assert(v < nvars);
8842  }
8843  (*nchgcoefs) += (v - startv);
8844 
8845  /* skip equal weights */
8846  while( weights[v] == newweight )
8847  ++v;
8848 
8849  if( v > 0 )
8850  {
8851  for( w = v; w < nvars; ++w )
8852  restsumweights += weights[w];
8853  }
8854  else
8855  restsumweights = consdata->weightsum;
8856 
8857  if( restsumweights < dualcapacity )
8858  {
8859  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8860  *
8861  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8862  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8863  */
8864  if( startv == v )
8865  {
8866  /* remove redundant variables */
8867  for( w = nvars - 1; w >= v; --w )
8868  {
8869  SCIP_CALL( delCoefPos(scip, cons, v) );
8870  ++(*nchgcoefs);
8871  }
8872 
8873 #ifndef NDEBUG
8874  /* each coefficients should exceed the dualcapacity by itself */
8875  for( ; w >= 0; --w )
8876  assert(weights[w] == dualcapacity);
8877 #endif
8878  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8879  * upgrade this constraint
8880  */
8881  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8882  assert(SCIPconsIsDeleted(cons));
8883 
8884  return SCIP_OKAY;
8885  }
8886 
8887  /* special case where we have three different coefficient types
8888  *
8889  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8890  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8891  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8892  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8893  */
8894  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8895  {
8896  SCIP_Longint newcap;
8897 
8898  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8899  for( w = nvars - 1; w >= v; --w )
8900  {
8901  if( weights[w] > 1 )
8902  {
8903  consdataChgWeight(consdata, w, 1LL);
8904  ++(*nchgcoefs);
8905  }
8906  }
8907 
8908  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8909  * dualcapacity
8910  */
8911  newweight = (SCIP_Longint)nvars - v;
8912  assert(newweight > 1);
8913  for( ; w >= startv; --w )
8914  {
8915  if( weights[w] > newweight )
8916  {
8917  consdataChgWeight(consdata, w, newweight);
8918  ++(*nchgcoefs);
8919  }
8920  else
8921  assert(weights[w] == newweight);
8922  }
8923 
8924  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8925  ++newweight;
8926  assert(newweight > 2);
8927  for( ; w >= 0; --w )
8928  {
8929  if( weights[w] > newweight )
8930  {
8931  consdataChgWeight(consdata, w, newweight);
8932  ++(*nchgcoefs);
8933  }
8934  else
8935  assert(weights[w] == newweight);
8936  }
8937 
8938  /* update the capacity */
8939  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8940  if( consdata->capacity > newcap )
8941  {
8942  consdata->capacity = newcap;
8943  ++(*nchgsides);
8944  }
8945  else
8946  assert(consdata->capacity == newcap);
8947  }
8948  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8949 
8950  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8951  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8952 
8953  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8954  * weight must not be sorted by their index
8955  */
8956 #ifndef NDEBUG
8957  for( w = nvars - 1; w > 0; --w )
8958  assert(weights[w] <= weights[w - 1]);
8959 #endif
8960  return SCIP_OKAY;
8961  }
8962 
8963  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8964  end = nvars - 2;
8965  while( end >= 0 && weights[end] == weights[end + 1] )
8966  {
8967  assert(end >= v);
8968  --end;
8969  }
8970 
8971  if( v >= end )
8972  goto TERMINATE;
8973 
8974  end = nvars - 2;
8975 
8976  /* can we stop early, another special reduction case might exist */
8977  if( 2 * weights[end] > dualcapacity )
8978  {
8979  restsumweights = 0;
8980 
8981  /* determine capacity of the small items */
8982  for( w = end + 1; w < nvars; ++w )
8983  restsumweights += weights[w];
8984 
8985  if( restsumweights * 2 <= dualcapacity )
8986  {
8987  /* check for further posssible reductions in the middle */
8988  while( v < end && restsumweights + weights[v] >= dualcapacity )
8989  ++v;
8990 
8991  if( v >= end )
8992  goto TERMINATE;
8993 
8994  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8995  if( (dualcapacity & 1) == 0 )
8996  {
8997  newweight = dualcapacity / 2;
8998 
8999  /* set all middle coefficients */
9000  for( ; v <= end; ++v )
9001  {
9002  if( weights[v] > newweight )
9003  {
9004  reductionsum += (weights[v] - newweight);
9005  consdataChgWeight(consdata, v, newweight);
9006  ++(*nchgcoefs);
9007  }
9008  }
9009  }
9010  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9011  * other coefficients by 2
9012  */
9013  else
9014  {
9015  /* correct the reductionsum */
9016  reductionsum *= 2;
9017 
9018  /* multiply big coefficients by 2 */
9019  for( w = 0; w < v; ++w )
9020  {
9021  consdataChgWeight(consdata, w, weights[w] * 2);
9022  }
9023 
9024  newweight = dualcapacity;
9025  /* set all middle coefficients */
9026  for( ; v <= end; ++v )
9027  {
9028  reductionsum += (2 * weights[v] - newweight);
9029  consdataChgWeight(consdata, v, newweight);
9030  }
9031 
9032  /* multiply small coefficients by 2 */
9033  for( w = end + 1; w < nvars; ++w )
9034  {
9035  consdataChgWeight(consdata, w, weights[w] * 2);
9036  }
9037  (*nchgcoefs) += nvars;
9038 
9039  dualcapacity *= 2;
9040  consdata->capacity *= 2;
9041  ++(*nchgsides);
9042  }
9043  }
9044 
9045  goto TERMINATE;
9046  }
9047 
9048  /* further reductions using the next possible coefficient sum
9049  *
9050  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9051  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9052  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9053  */
9054  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9055  for( k = 0; k < 4; ++k )
9056  {
9057  /* determine next minimal coefficient sum */
9058  switch( k )
9059  {
9060  case 0:
9061  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9062  break;
9063  case 1:
9064  assert(nvars >= 3);
9065  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9066  break;
9067  case 2:
9068  assert(nvars >= 4);
9069  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9070  {
9071  sumcoefcase = TRUE;
9072  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9073  }
9074  else
9075  {
9076  sumcoefcase = FALSE;
9077  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9078  }
9079  break;
9080  case 3:
9081  assert(nvars >= 5);
9082  if( sumcoefcase )
9083  {
9084  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9085  }
9086  else
9087  {
9088  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9089  }
9090  break;
9091  default:
9092  return SCIP_ERROR;
9093  }
9094 
9095  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9096  minweight = weights[end];
9097  while( minweight <= sumcoef )
9098  {
9099  newweight = dualcapacity - minweight;
9100  startv = v;
9101  assert(v < nvars);
9102 
9103  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9104  /* shrink big coefficients */
9105  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9106  {
9107  reductionsum += (weights[v] - newweight);
9108  consdataChgWeight(consdata, v, newweight);
9109  ++v;
9110  assert(v < nvars);
9111  }
9112  (*nchgcoefs) += (v - startv);
9113 
9114  /* skip unchangable weights */
9115  while( weights[v] + minweight == dualcapacity )
9116  {
9117  assert(v < nvars);
9118  ++v;
9119  }
9120 
9121  --end;
9122  /* skip same end weights */
9123  while( end >= 0 && weights[end] == weights[end + 1] )
9124  --end;
9125 
9126  if( v >= end )
9127  goto TERMINATE;
9128 
9129  minweight = weights[end];
9130  }
9131 
9132  if( v >= end )
9133  goto TERMINATE;
9134 
9135  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9136  if( sumcoef < minweight )
9137  {
9138  minweight = sumcoef;
9139  newweight = dualcapacity - minweight;
9140  startv = v;
9141  assert(v < nvars);
9142 
9143  /* shrink big coefficients */
9144  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9145  {
9146  reductionsum += (weights[v] - newweight);
9147  consdataChgWeight(consdata, v, newweight);
9148  ++v;
9149  assert(v < nvars);
9150  }
9151  (*nchgcoefs) += (v - startv);
9152 
9153  /* skip unchangable weights */
9154  while( weights[v] + minweight == dualcapacity )
9155  {
9156  assert(v < nvars);
9157  ++v;
9158  }
9159  }
9160 
9161  if( v >= end )
9162  goto TERMINATE;
9163 
9164  /* can we stop early, another special reduction case might exist */
9165  if( 2 * weights[end] > dualcapacity )
9166  {
9167  restsumweights = 0;
9168 
9169  /* determine capacity of the small items */
9170  for( w = end + 1; w < nvars; ++w )
9171  restsumweights += weights[w];
9172 
9173  if( restsumweights * 2 <= dualcapacity )
9174  {
9175  /* check for further posssible reductions in the middle */
9176  while( v < end && restsumweights + weights[v] >= dualcapacity )
9177  ++v;
9178 
9179  if( v >= end )
9180  goto TERMINATE;
9181 
9182  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9183  if( (dualcapacity & 1) == 0 )
9184  {
9185  newweight = dualcapacity / 2;
9186 
9187  /* set all middle coefficients */
9188  for( ; v <= end; ++v )
9189  {
9190  if( weights[v] > newweight )
9191  {
9192  reductionsum += (weights[v] - newweight);
9193  consdataChgWeight(consdata, v, newweight);
9194  ++(*nchgcoefs);
9195  }
9196  }
9197  }
9198  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9199  * other coefficients by 2
9200  */
9201  else
9202  {
9203  /* correct the reductionsum */
9204  reductionsum *= 2;
9205 
9206  /* multiply big coefficients by 2 */
9207  for( w = 0; w < v; ++w )
9208  {
9209  consdataChgWeight(consdata, w, weights[w] * 2);
9210  }
9211 
9212  newweight = dualcapacity;
9213  /* set all middle coefficients */
9214  for( ; v <= end; ++v )
9215  {
9216  reductionsum += (2 * weights[v] - newweight);
9217  consdataChgWeight(consdata, v, newweight);
9218  }
9219 
9220  /* multiply small coefficients by 2 */
9221  for( w = end + 1; w < nvars; ++w )
9222  {
9223  consdataChgWeight(consdata, w, weights[w] * 2);
9224  }
9225  (*nchgcoefs) += nvars;
9226 
9227  dualcapacity *= 2;
9228  consdata->capacity *= 2;
9229  ++(*nchgsides);
9230  }
9231  }
9232 
9233  goto TERMINATE;
9234  }
9235 
9236  /* cannot tighten any further */
9237  if( 2 * sumcoef > dualcapacity )
9238  goto TERMINATE;
9239  }
9240  }
9241  }
9242 
9243  TERMINATE:
9244  /* correct capacity */
9245  if( reductionsum > 0 )
9246  {
9247  assert(v > 0);
9248 
9249  consdata->capacity -= reductionsum;
9250  ++(*nchgsides);
9251 
9252  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9253  }
9254  assert(weights[0] <= consdata->capacity);
9255 
9256  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9257  * weight must not be sorted by their index
9258  */
9259 #ifndef NDEBUG
9260  for( w = nvars - 1; w > 0; --w )
9261  assert(weights[w] <= weights[w - 1]);
9262 #endif
9263 
9264  if( oldnchgcoefs < *nchgcoefs )
9265  {
9266  assert(!SCIPconsIsDeleted(cons));
9267 
9268  /* it might be that we can divide the weights by their greatest common divisor */
9269  normalizeWeights(cons, nchgcoefs, nchgsides);
9270  }
9271  else
9272  {
9273  assert(oldnchgcoefs == *nchgcoefs);
9274  assert(oldnchgsides == *nchgsides);
9275  }
9276 
9277  return SCIP_OKAY;
9278 }
9279 
9280 
9281 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9282 static
9284  SCIP* scip, /**< SCIP data structure */
9285  SCIP_CONS* cons, /**< knapsack constraint */
9286  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9287  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9288  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9289  )
9290 {
9291  SCIP_VAR** vars;
9292  SCIP_CONSDATA* consdata;
9293  SCIP_Longint* weights;
9294  SCIP_Longint capacity;
9295  SCIP_Bool infeasible;
9296  SCIP_Bool fixed;
9297  int nvars;
9298  int v;
9299 
9300  assert(scip != NULL);
9301  assert(cons != NULL);
9302  assert(nfixedvars != NULL);
9303  assert(ndelconss != NULL);
9304  assert(nchgcoefs != NULL);
9305 
9306  consdata = SCIPconsGetData(cons);
9307  assert(consdata != NULL);
9308 
9309  nvars = consdata->nvars;
9310 
9311  /* no variables left, then delete constraint */
9312  if( nvars == 0 )
9313  {
9314  assert(consdata->capacity >= 0);
9315 
9316  SCIP_CALL( SCIPdelCons(scip, cons) );
9317  ++(*ndelconss);
9318 
9319  return SCIP_OKAY;
9320  }
9321 
9322  /* sort items */
9323  sortItems(consdata);
9324 
9325  vars = consdata->vars;
9326  weights = consdata->weights;
9327  capacity = consdata->capacity;
9328  v = 0;
9329 
9330  /* check for weights bigger than the capacity */
9331  while( v < nvars && weights[v] > capacity )
9332  {
9333  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9334  assert(!infeasible);
9335 
9336  if( fixed )
9337  ++(*nfixedvars);
9338 
9339  ++v;
9340  }
9341 
9342  /* if we fixed at least one variable we need to delete them from the constraint */
9343  if( v > 0 )
9344  {
9345  if( v == nvars )
9346  {
9347  SCIP_CALL( SCIPdelCons(scip, cons) );
9348  ++(*ndelconss);
9349 
9350  return SCIP_OKAY;
9351  }
9352 
9353  /* delete all position from back to front */
9354  for( --v; v >= 0; --v )
9355  {
9356  SCIP_CALL( delCoefPos(scip, cons, v) );
9357  ++(*nchgcoefs);
9358  }
9359 
9360  /* sort items again because of deletion */
9361  sortItems(consdata);
9362  assert(vars == consdata->vars);
9363  assert(weights == consdata->weights);
9364  }
9365  assert(consdata->sorted);
9366  assert(weights[0] <= capacity);
9367 
9368  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9369  {
9370  SCIP_CALL( SCIPdelCons(scip, cons) );
9371  ++(*ndelconss);
9372  }
9373 
9374  return SCIP_OKAY;
9375 }
9376 
9377 
9378 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9379  *
9380  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9381  *
9382  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9383  *
9384  * the above constraint can be changed to
9385  *
9386  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9387  *
9388  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9389  *
9390  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9391  *
9392  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9393  * constraint further, e.g.
9394  *
9395  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9396  * => 2x1 + x2 + x3 + x4 <= 2
9397  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9398  */
9399 static
9401  SCIP* scip, /**< SCIP data structure */
9402  SCIP_CONS* cons, /**< knapsack constraint */
9403  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9404  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9405  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9406  int* nchgsides, /**< pointer to store the amount of changed sides */
9407  int* naddconss, /**< pointer to count number of added constraints */
9408  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9409  )
9410 {
9411  SCIP_VAR** vars;
9412  SCIP_CONSDATA* consdata;
9413  SCIP_Longint* weights;
9414  SCIP_Longint restweight;
9415  SCIP_Longint newweight;
9416  SCIP_Longint weight;
9417  SCIP_Longint oldgcd;
9418  SCIP_Longint rest;
9419  SCIP_Longint gcd;
9420  int oldnchgcoefs;
9421  int oldnchgsides;
9422  int candpos;
9423  int candpos2;
9424  int offsetv;
9425  int nvars;
9426  int v;
9427 
9428  assert(scip != NULL);
9429  assert(cons != NULL);
9430  assert(nfixedvars != NULL);
9431  assert(ndelconss != NULL);
9432  assert(nchgcoefs != NULL);
9433  assert(nchgsides != NULL);
9434  assert(naddconss != NULL);
9435  assert(cutoff != NULL);
9436  assert(!SCIPconsIsModifiable(cons));
9437 
9438  consdata = SCIPconsGetData(cons);
9439  assert( consdata != NULL );
9440 
9441  *cutoff = FALSE;
9442 
9443  /* remove double enties and also combinations of active and negated variables */
9444  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9445  assert(consdata->merged);
9446  if( *cutoff )
9447  return SCIP_OKAY;
9448 
9449  assert(consdata->capacity >= 0);
9450 
9451  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9452  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9453 
9454  if( SCIPconsIsDeleted(cons) )
9455  return SCIP_OKAY;
9456 
9457  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9458  {
9459  /* 1. dual weights tightening */
9460  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9461 
9462  if( SCIPconsIsDeleted(cons) )
9463  return SCIP_OKAY;
9464  /* 2. delete redundant variables */
9465  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9466 
9467  if( SCIPconsIsDeleted(cons) )
9468  return SCIP_OKAY;
9469  }
9470 
9471  weights = consdata->weights;
9472  nvars = consdata->nvars;
9473 
9474 #ifndef NDEBUG
9475  /* constraint might not be sorted, but the weights are already sorted */
9476  for( v = nvars - 1; v > 0; --v )
9477  assert(weights[v] <= weights[v-1]);
9478 #endif
9479 
9480  /* determine greatest common divisor */
9481  gcd = weights[nvars - 1];
9482  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9483  {
9484  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9485  }
9486 
9487  /* divide the constraint by their greatest common divisor */
9488  if( gcd >= 2 )
9489  {
9490  for( v = nvars - 1; v >= 0; --v )
9491  {
9492  consdataChgWeight(consdata, v, weights[v]/gcd);
9493  }
9494  (*nchgcoefs) += nvars;
9495 
9496  consdata->capacity /= gcd;
9497  (*nchgsides)++;
9498  }
9499  assert(consdata->nvars == nvars);
9500 
9501  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9502  * must not be sorted by their index
9503  */
9504 #ifndef NDEBUG
9505  for( v = nvars - 1; v > 0; --v )
9506  assert(weights[v] <= weights[v-1]);
9507 #endif
9508 
9509  /* 3. start gcd procedure for all variables */
9510  do
9511  {
9512  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9513  SCIPdebug( oldnchgsides = *nchgsides; )
9514 
9515  vars = consdata->vars;
9516  weights = consdata->weights;
9517  nvars = consdata->nvars;
9518 
9519  /* stop if we have two coefficients which are one in absolute value */
9520  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9521  return SCIP_OKAY;
9522 
9523  v = 0;
9524  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9525  * gcd
9526  */
9527  while( weights[v] == consdata->capacity )
9528  {
9529  ++v;
9530  assert(v < nvars);
9531  }
9532 
9533  /* all but one variable are as big as the capacity, this is handled elsewhere */
9534  if( v == nvars - 1 )
9535  return SCIP_OKAY;
9536 
9537  offsetv = v;
9538 
9539  gcd = -1;
9540  candpos = -1;
9541  candpos2 = -1;
9542 
9543  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9544  * change the coefficient
9545  */
9546  for( v = nvars - 1; v >= offsetv; --v )
9547  {
9548  weight = weights[v];
9549  assert(weight >= 1);
9550 
9551  oldgcd = gcd;
9552 
9553  if( gcd == -1 )
9554  {
9555  gcd = weights[v];
9556  assert(gcd >= 1);
9557  }
9558  else
9559  {
9560  /* calculate greatest common divisor for all variables */
9561  gcd = SCIPcalcGreComDiv(gcd, weight);
9562  }
9563 
9564  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9565  * can terminate
9566  */
9567  if( gcd == 1 )
9568  {
9569  /* found candidate */
9570  if( candpos == -1 )
9571  {
9572  gcd = oldgcd;
9573  candpos = v;
9574 
9575  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9576  if( v == nvars - 2 )
9577  candpos2 = v + 1;
9578  }
9579  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9580  else
9581  {
9582  if( candpos == v + 1 && candpos2 == v + 2 )
9583  {
9584  assert(candpos2 == nvars - 1);
9585 
9586  /* take new candidates */
9587  candpos = candpos2;
9588 
9589  /* recalculate gcd from scratch */
9590  gcd = weights[v+1];
9591  assert(gcd >= 1);
9592 
9593  /* calculate greatest common divisor for variables */
9594  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9595  if( gcd == 1 )
9596  return SCIP_OKAY;
9597  }
9598  else
9599  /* cannot determine a possible coefficient for reduction */
9600  return SCIP_OKAY;
9601  }
9602  }
9603  }
9604  assert(gcd >= 2);
9605 
9606  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9607  * further
9608  */
9609  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9610 
9611  /* determine the remainder of the capacity and the gcd */
9612  rest = consdata->capacity % gcd;
9613  assert(rest >= 0);
9614  assert(rest < gcd);
9615 
9616  if( candpos == -1 )
9617  {
9618  /* we assume that the constraint was normalized */
9619  assert(rest > 0);
9620 
9621  /* replace old with new capacity */
9622  consdata->capacity -= rest;
9623  ++(*nchgsides);
9624 
9625  /* replace old big coefficients with new capacity */
9626  for( v = 0; v < offsetv; ++v )
9627  {
9628  consdataChgWeight(consdata, v, consdata->capacity);
9629  }
9630 
9631  *nchgcoefs += offsetv;
9632  goto CONTINUE;
9633  }
9634 
9635  /* determine the remainder of the coefficient candidate and the gcd */
9636  restweight = weights[candpos] % gcd;
9637  assert(restweight >= 1);
9638  assert(restweight < gcd);
9639 
9640  /* calculate new coefficient */
9641  if( restweight > rest )
9642  newweight = weights[candpos] - restweight + gcd;
9643  else
9644  newweight = weights[candpos] - restweight;
9645 
9646  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9647 
9648  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);
9649 
9650  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9651  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9652  */
9653  if( newweight == 0 && offsetv > 0 )
9654  return SCIP_OKAY;
9655 
9656  if( rest > 0 )
9657  {
9658  /* replace old with new capacity */
9659  consdata->capacity -= rest;
9660  ++(*nchgsides);
9661 
9662  /* replace old big coefficients with new capacity */
9663  for( v = 0; v < offsetv; ++v )
9664  {
9665  consdataChgWeight(consdata, v, consdata->capacity);
9666  }
9667 
9668  *nchgcoefs += offsetv;
9669  }
9670 
9671  if( newweight == 0 )
9672  {
9673  /* delete redundant coefficient */
9674  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9675  assert(consdata->nvars == nvars - 1);
9676  --nvars;
9677  }
9678  else
9679  {
9680  /* replace old with new coefficient */
9681  consdataChgWeight(consdata, candpos, newweight);
9682  }
9683  ++(*nchgcoefs);
9684 
9685  assert(consdata->vars == vars);
9686  assert(consdata->nvars == nvars);
9687  assert(consdata->weights == weights);
9688 
9689  CONTINUE:
9690  /* now constraint can be normalized, dividing it by the gcd */
9691  for( v = nvars - 1; v >= 0; --v )
9692  {
9693  consdataChgWeight(consdata, v, weights[v]/gcd);
9694  }
9695  (*nchgcoefs) += nvars;
9696 
9697  consdata->capacity /= gcd;
9698  ++(*nchgsides);
9699 
9700  SCIPdebugPrintCons(scip, cons, NULL);
9701 
9702  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));
9703  }
9704  while( nvars >= 2 );
9705 
9706  return SCIP_OKAY;
9707 }
9708 
9709 
9710 /** inserts an element into the list of binary zero implications */
9711 static
9713  SCIP* scip, /**< SCIP data structure */
9714  int** liftcands, /**< array of the lifting candidates */
9715  int* nliftcands, /**< number of lifting candidates */
9716  int** firstidxs, /**< array of first zeroitems indices */
9717  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9718  int** zeroitems, /**< pointer to zero items array */
9719  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9720  int* zeroitemssize, /**< pointer to size of zero items array */
9721  int* nzeroitems, /**< pointer to length of zero items array */
9722  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9723  SCIP_Bool value, /**< value v of variable y in implication */
9724  int knapsackidx, /**< index of variable x in knapsack */
9725  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9726  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9727  )
9728 {
9729  int nzeros;
9730 
9731  assert(liftcands != NULL);
9732  assert(liftcands[value] != NULL);
9733  assert(nliftcands != NULL);
9734  assert(firstidxs != NULL);
9735  assert(firstidxs[value] != NULL);
9736  assert(zeroweightsums != NULL);
9737  assert(zeroweightsums[value] != NULL);
9738  assert(zeroitems != NULL);
9739  assert(nextidxs != NULL);
9740  assert(zeroitemssize != NULL);
9741  assert(nzeroitems != NULL);
9742  assert(*nzeroitems <= *zeroitemssize);
9743  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9744  assert(memlimitreached != NULL);
9745 
9746  nzeros = *nzeroitems;
9747 
9748  /* allocate enough memory */
9749  if( nzeros == *zeroitemssize )
9750  {
9751  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9752  * this can be too huge - abort on memory limit
9753  */
9754  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9755  {
9756  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9757  *zeroitemssize);
9758  *memlimitreached = TRUE;
9759  return SCIP_OKAY;
9760  }
9761  *zeroitemssize *= 2;
9762  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9763  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9764  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9765  }
9766  assert(nzeros < *zeroitemssize);
9767 
9768  if( *memlimitreached )
9769  *memlimitreached = FALSE;
9770 
9771  /* insert element */
9772  (*zeroitems)[nzeros] = knapsackidx;
9773  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9774  if( firstidxs[value][probindex] == 0 )
9775  {
9776  liftcands[value][nliftcands[value]] = probindex;
9777  ++nliftcands[value];
9778  }
9779  firstidxs[value][probindex] = nzeros;
9780  ++(*nzeroitems);
9781  zeroweightsums[value][probindex] += knapsackweight;
9782 
9783  return SCIP_OKAY;
9784 }
9785 
9786 #define MAX_CLIQUELENGTH 50
9787 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9788  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9789  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9790  * if cliqueweightsum(xi == v) < capacity:
9791  * - fixing variable xi to v would make the knapsack constraint redundant
9792  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9793  * redundancy effect:
9794  * wi' := capacity - cliqueweightsum(xi == v)
9795  * this rule can also be applied to binary variables not in the knapsack!
9796  */
9797 static
9799  SCIP* scip, /**< SCIP data structure */
9800  SCIP_CONS* cons, /**< knapsack constraint */
9801  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9802  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9803  )
9804 {
9805  SCIP_CONSDATA* consdata;
9806  SCIP_VAR** binvars;
9807  int nbinvars;
9808  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9809  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9810  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9811  int* zeroitems; /* item number in knapsack that is implied to zero */
9812  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9813  int zeroitemssize;
9814  int nzeroitems;
9815  SCIP_Bool* zeroiteminserted[2];
9816  SCIP_Bool memlimitreached;
9817  int nliftcands[2];
9818  SCIP_Bool* cliqueused;
9819  SCIP_Bool* itemremoved;
9820  SCIP_Longint maxcliqueweightsum;
9821  SCIP_VAR** addvars;
9822  SCIP_Longint* addweights;
9823  SCIP_Longint addweightsum;
9824  int nvars;
9825  int cliquenum;
9826  int naddvars;
9827  int val;
9828  int i;
9829 
9830  int* tmpindices;
9831  SCIP_Bool* tmpboolindices;
9832  int* tmpindices2;
9833  SCIP_Bool* tmpboolindices2;
9834  int* tmpindices3;
9835  SCIP_Bool* tmpboolindices3;
9836  int tmp;
9837  int tmp2;
9838  int tmp3;
9839  SCIP_CONSHDLR* conshdlr;
9840  SCIP_CONSHDLRDATA* conshdlrdata;
9841 
9842  assert(nchgcoefs != NULL);
9843  assert(!SCIPconsIsModifiable(cons));
9844 
9845  consdata = SCIPconsGetData(cons);
9846  assert(consdata != NULL);
9847  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9848  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9849  assert(consdata->nvars > 0);
9850  assert(consdata->merged);
9851 
9852  nvars = consdata->nvars;
9853 
9854  /* check if the knapsack has too many items/cliques for applying this costly method */
9855  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9856  return SCIP_OKAY;
9857 
9858  /* sort items, s.t. the heaviest one is in the first position */
9859  sortItems(consdata);
9860 
9861  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9862  return SCIP_OKAY;
9863 
9864  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9865  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9866  assert(nbinvars > 0);
9867  binvars = SCIPgetVars(scip);
9868 
9869  /* get conshdlrdata to use cleared memory */
9870  conshdlr = SCIPconsGetHdlr(cons);
9871  assert(conshdlr != NULL);
9872  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9873  assert(conshdlrdata != NULL);
9874 
9875  /* allocate temporary memory for the list of implied to zero variables */
9876  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9877  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9878  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9879 
9880  assert(conshdlrdata->ints1size > 0);
9881  assert(conshdlrdata->ints2size > 0);
9882  assert(conshdlrdata->longints1size > 0);
9883  assert(conshdlrdata->longints2size > 0);
9884 
9885  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9886  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9887  * transform all integers into their binary representation then it maybe happens
9888  */
9889  if( conshdlrdata->ints1size < nbinvars )
9890  {
9891  int oldsize = conshdlrdata->ints1size;
9892 
9893  conshdlrdata->ints1size = nbinvars;
9894  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9895  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9896  }
9897  if( conshdlrdata->ints2size < nbinvars )
9898  {
9899  int oldsize = conshdlrdata->ints2size;
9900 
9901  conshdlrdata->ints2size = nbinvars;
9902  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9903  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9904  }
9905  if( conshdlrdata->longints1size < nbinvars )
9906  {
9907  int oldsize = conshdlrdata->longints1size;
9908 
9909  conshdlrdata->longints1size = nbinvars;
9910  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9911  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9912  }
9913  if( conshdlrdata->longints2size < nbinvars )
9914  {
9915  int oldsize = conshdlrdata->longints2size;
9916 
9917  conshdlrdata->longints2size = nbinvars;
9918  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9919  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9920  }
9921 
9922  firstidxs[0] = conshdlrdata->ints1;
9923  firstidxs[1] = conshdlrdata->ints2;
9924  zeroweightsums[0] = conshdlrdata->longints1;
9925  zeroweightsums[1] = conshdlrdata->longints2;
9926 
9927  /* check for cleared arrays, all entries are zero */
9928 #ifndef NDEBUG
9929  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9930  {
9931  assert(firstidxs[0][tmp] == 0);
9932  assert(firstidxs[1][tmp] == 0);
9933  assert(zeroweightsums[0][tmp] == 0);
9934  assert(zeroweightsums[1][tmp] == 0);
9935  }
9936 #endif
9937 
9938  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9939  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9940 
9941  zeroitems[0] = -1; /* dummy element */
9942  nextidxs[0] = -1;
9943  nzeroitems = 1;
9944  nliftcands[0] = 0;
9945  nliftcands[1] = 0;
9946 
9947  assert(conshdlrdata->bools1size > 0);
9948  assert(conshdlrdata->bools2size > 0);
9949 
9950  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9951  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9952  * transform all integers into their binary representation then it maybe happens
9953  */
9954  if( conshdlrdata->bools1size < nbinvars )
9955  {
9956  int oldsize = conshdlrdata->bools1size;
9957 
9958  conshdlrdata->bools1size = nbinvars;
9959  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9960  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9961  }
9962  if( conshdlrdata->bools2size < nbinvars )
9963  {
9964  int oldsize = conshdlrdata->bools2size;
9965 
9966  conshdlrdata->bools2size = nbinvars;
9967  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9968  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9969  }
9970 
9971  zeroiteminserted[0] = conshdlrdata->bools1;
9972  zeroiteminserted[1] = conshdlrdata->bools2;
9973 
9974  /* check for cleared arrays, all entries are zero */
9975 #ifndef NDEBUG
9976  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9977  {
9978  assert(zeroiteminserted[0][tmp] == 0);
9979  assert(zeroiteminserted[1][tmp] == 0);
9980  }
9981 #endif
9982 
9983  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9984  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9985  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9986  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9987  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9988  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9989 
9990  tmp2 = 0;
9991  tmp3 = 0;
9992 
9993  memlimitreached = FALSE;
9994  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9995  {
9996  SCIP_CLIQUE** cliques;
9997  SCIP_VAR* var;
9998  SCIP_Longint weight;
9999  SCIP_Bool value;
10000  int varprobindex;
10001  int ncliques;
10002  int j;
10003 
10004  tmp = 0;
10005 
10006  /* get corresponding active problem variable */
10007  var = consdata->vars[i];
10008  weight = consdata->weights[i];
10009  value = TRUE;
10010  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10011  varprobindex = SCIPvarGetProbindex(var);
10012  assert(0 <= varprobindex && varprobindex < nbinvars);
10013 
10014  /* update the zeroweightsum */
10015  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10016  tmpboolindices3[tmp3] = !value;
10017  tmpindices3[tmp3] = varprobindex;
10018  ++tmp3;
10019 
10020  /* initialize the arrays of inserted zero items */
10021  /* first add the implications (~x == 1 -> x == 0) */
10022  {
10023  SCIP_Bool implvalue;
10024  int probindex;
10025 
10026  probindex = SCIPvarGetProbindex(var);
10027  assert(0 <= probindex && probindex < nbinvars);
10028 
10029  implvalue = !value;
10030 
10031  /* insert the item into the list of the implied variable/value */
10032  assert( !zeroiteminserted[implvalue][probindex] );
10033 
10034  if( firstidxs[implvalue][probindex] == 0 )
10035  {
10036  tmpboolindices2[tmp2] = implvalue;
10037  tmpindices2[tmp2] = probindex;
10038  ++tmp2;
10039  }
10040  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10041  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10042  &memlimitreached) );
10043  zeroiteminserted[implvalue][probindex] = TRUE;
10044  tmpboolindices[tmp] = implvalue;
10045  tmpindices[tmp] = probindex;
10046  ++tmp;
10047  }
10048 
10049  /* get the cliques where the knapsack item is member of with value 1 */
10050  ncliques = SCIPvarGetNCliques(var, value);
10051  cliques = SCIPvarGetCliques(var, value);
10052  for( j = 0; j < ncliques && !memlimitreached; ++j )
10053  {
10054  SCIP_VAR** cliquevars;
10055  SCIP_Bool* cliquevalues;
10056  int ncliquevars;
10057  int k;
10058 
10059  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10060 
10061  /* discard big cliques */
10062  if( ncliquevars > MAX_CLIQUELENGTH )
10063  continue;
10064 
10065  cliquevars = SCIPcliqueGetVars(cliques[j]);
10066  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10067 
10068  for( k = ncliquevars - 1; k >= 0; --k )
10069  {
10070  SCIP_Bool implvalue;
10071  int probindex;
10072 
10073  if( var == cliquevars[k] )
10074  continue;
10075 
10076  probindex = SCIPvarGetProbindex(cliquevars[k]);
10077  if( probindex == -1 )
10078  continue;
10079 
10080  assert(0 <= probindex && probindex < nbinvars);
10081  implvalue = cliquevalues[k];
10082 
10083  /* insert the item into the list of the clique variable/value */
10084  if( !zeroiteminserted[implvalue][probindex] )
10085  {
10086  if( firstidxs[implvalue][probindex] == 0 )
10087  {
10088  tmpboolindices2[tmp2] = implvalue;
10089  tmpindices2[tmp2] = probindex;
10090  ++tmp2;
10091  }
10092 
10093  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10094  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10095  &memlimitreached) );
10096  zeroiteminserted[implvalue][probindex] = TRUE;
10097  tmpboolindices[tmp] = implvalue;
10098  tmpindices[tmp] = probindex;
10099  ++tmp;
10100 
10101  if( memlimitreached )
10102  break;
10103  }
10104  }
10105  }
10106  /* clear zeroiteminserted */
10107  for( --tmp; tmp >= 0; --tmp)
10108  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10109  }
10110  SCIPfreeBufferArray(scip, &tmpboolindices);
10111 
10112  /* calculate the clique partition and the maximal sum of weights using the clique information */
10113  assert(consdata->sorted);
10114  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10115 
10116  assert(conshdlrdata->bools3size > 0);
10117 
10118  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10119  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10120  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10121  */
10122  if( conshdlrdata->bools3size < consdata->nvars )
10123  {
10124  int oldsize = conshdlrdata->bools3size;
10125 
10126  conshdlrdata->bools3size = consdata->nvars;;
10127  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10128  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10129  }
10130 
10131  cliqueused = conshdlrdata->bools3;
10132 
10133  /* check for cleared array, all entries are zero */
10134 #ifndef NDEBUG
10135  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10136  assert(cliqueused[tmp] == 0);
10137 #endif
10138 
10139  maxcliqueweightsum = 0;
10140  tmp = 0;
10141 
10142  /* calculates maximal weight of cliques */
10143  for( i = 0; i < consdata->nvars; ++i )
10144  {
10145  cliquenum = consdata->cliquepartition[i];
10146  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10147 
10148  if( !cliqueused[cliquenum] )
10149  {
10150  maxcliqueweightsum += consdata->weights[i];
10151  cliqueused[cliquenum] = TRUE;
10152  tmpindices[tmp] = cliquenum;
10153  ++tmp;
10154  }
10155  }
10156  /* clear cliqueused */
10157  for( --tmp; tmp >= 0; --tmp)
10158  cliqueused[tmp] = FALSE;
10159 
10160  assert(conshdlrdata->bools4size > 0);
10161 
10162  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10163  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10164  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10165  */
10166  if( conshdlrdata->bools4size < consdata->nvars )
10167  {
10168  int oldsize = conshdlrdata->bools4size;
10169 
10170  conshdlrdata->bools4size = consdata->nvars;
10171  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10172  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10173  }
10174 
10175  itemremoved = conshdlrdata->bools4;
10176 
10177  /* check for cleared array, all entries are zero */
10178 #ifndef NDEBUG
10179  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10180  assert(itemremoved[tmp] == 0);
10181 #endif
10182 
10183  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10184  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10185  * included in subsequent cliqueweightsum calculations)
10186  */
10187  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10188  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10189  naddvars = 0;
10190  addweightsum = 0;
10191  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10192  {
10193  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10194  {
10195  SCIP_Longint cliqueweightsum;
10196  int probindex;
10197  int idx;
10198  int j;
10199 
10200  tmp = 0;
10201 
10202  probindex = liftcands[val][i];
10203  assert(0 <= probindex && probindex < nbinvars);
10204 
10205  /* ignore empty zero lists and variables that cannot be lifted anyways */
10206  if( firstidxs[val][probindex] == 0
10207  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10208  continue;
10209 
10210  /* mark the items that are implied to zero by setting the current variable to the current value */
10211  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10212  {
10213  assert(0 < idx && idx < nzeroitems);
10214  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10215  itemremoved[zeroitems[idx]] = TRUE;
10216  }
10217 
10218  /* calculate the residual cliqueweight sum */
10219  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10220  for( j = 0; j < consdata->nvars; ++j )
10221  {
10222  cliquenum = consdata->cliquepartition[j];
10223  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10224  if( !itemremoved[j] )
10225  {
10226  if( !cliqueused[cliquenum] )
10227  {
10228  cliqueweightsum += consdata->weights[j];
10229  cliqueused[cliquenum] = TRUE;
10230  tmpindices[tmp] = cliquenum;
10231  ++tmp;
10232  }
10233 
10234  if( cliqueweightsum >= consdata->capacity )
10235  break;
10236  }
10237  }
10238 
10239  /* check if the weight of the variable/value can be increased */
10240  if( cliqueweightsum < consdata->capacity )
10241  {
10242  SCIP_VAR* var;
10243  SCIP_Longint weight;
10244 
10245  /* insert the variable (with value TRUE) in the list of additional items */
10246  assert(naddvars < 2*nbinvars);
10247  var = binvars[probindex];
10248  if( val == FALSE )
10249  {
10250  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10251  }
10252  weight = consdata->capacity - cliqueweightsum;
10253  addvars[naddvars] = var;
10254  addweights[naddvars] = weight;
10255  addweightsum += weight;
10256  naddvars++;
10257 
10258  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10259  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10260  }
10261 
10262  /* clear itemremoved */
10263  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10264  {
10265  assert(0 < idx && idx < nzeroitems);
10266  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10267  itemremoved[zeroitems[idx]] = FALSE;
10268  }
10269  /* clear cliqueused */
10270  for( --tmp; tmp >= 0; --tmp)
10271  cliqueused[tmpindices[tmp]] = FALSE;
10272  }
10273  }
10274 
10275  /* clear part of zeroweightsums */
10276  for( --tmp3; tmp3 >= 0; --tmp3)
10277  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10278 
10279  /* clear rest of zeroweightsums and firstidxs */
10280  for( --tmp2; tmp2 >= 0; --tmp2)
10281  {
10282  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10283  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10284  }
10285 
10286  /* add all additional item weights */
10287  for( i = 0; i < naddvars; ++i )
10288  {
10289  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10290  }
10291  *nchgcoefs += naddvars;
10292 
10293  if( naddvars > 0 )
10294  {
10295  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10296  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10297  }
10298 
10299  /* free temporary memory */
10300  SCIPfreeBufferArray(scip, &addweights);
10301  SCIPfreeBufferArray(scip, &addvars);
10302  SCIPfreeBufferArray(scip, &tmpindices);
10303  SCIPfreeBufferArray(scip, &tmpindices2);
10304  SCIPfreeBufferArray(scip, &tmpindices3);
10305  SCIPfreeBufferArray(scip, &tmpboolindices2);
10306  SCIPfreeBufferArray(scip, &tmpboolindices3);
10307  SCIPfreeBufferArray(scip, &nextidxs);
10308  SCIPfreeBufferArray(scip, &zeroitems);
10309  SCIPfreeBufferArray(scip, &liftcands[1]);
10310  SCIPfreeBufferArray(scip, &liftcands[0]);
10311 
10312  return SCIP_OKAY;
10313 }
10314 
10315 /** tightens item weights and capacity in presolving:
10316  * given a knapsack sum(wi*xi) <= capacity
10317  * (1) let weightsum := sum(wi)
10318  * if weightsum - wi < capacity:
10319  * - not using item i would make the knapsack constraint redundant
10320  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10321  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10322  * - change coefficients:
10323  * wi' := weightsum - capacity
10324  * capacity' := capacity - (wi - wi')
10325  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10326  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10327  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10328  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10329  * can be multiple times the same weight, this can be improved
10330  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10331  * weight, to capacity - lastmininmalweightsum, e.g. :
10332  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10333  * -> minimal weightsums: 5, 5, 10, 10
10334  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10335  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10336  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10337  * (3) let W(C) be the maximal weight of clique C,
10338  * cliqueweightsum := sum(W(C))
10339  * if cliqueweightsum - W(C) < capacity:
10340  * - not using any item of C would make the knapsack constraint redundant
10341  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10342  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10343  * - change coefficients:
10344  * delta := capacity - (cliqueweightsum - W(C))
10345  * wi' := max(wi - delta, 0)
10346  * capacity' := capacity - delta
10347  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10348  * introduce infeasible solutions.
10349  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10350  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10351  * if cliqueweightsum(xi == v) < capacity:
10352  * - fixing variable xi to v would make the knapsack constraint redundant
10353  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10354  * redundancy effect:
10355  * wi' := capacity - cliqueweightsum(xi == v)
10356  * This rule can also be applied to binary variables not in the knapsack!
10357  * (5) if min{w} + wi > capacity:
10358  * - using item i would force to fix other items to zero
10359  * - wi can be increased to the capacity
10360  */
10361 static
10363  SCIP* scip, /**< SCIP data structure */
10364  SCIP_CONS* cons, /**< knapsack constraint */
10365  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10366  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10367  int* nchgsides, /**< pointer to count number of side changes */
10368  int* naddconss, /**< pointer to count number of added constraints */
10369  int* ndelconss, /**< pointer to count number of deleted constraints */
10370  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10371  )
10372 {
10373  SCIP_CONSHDLRDATA* conshdlrdata;
10374  SCIP_CONSDATA* consdata;
10375  SCIP_Longint* weights;
10376  SCIP_Longint sumcoef;
10377  SCIP_Longint capacity;
10378  SCIP_Longint newweight;
10379  SCIP_Longint maxweight;
10380  SCIP_Longint minweight;
10381  SCIP_Bool sumcoefcase = FALSE;
10382  int startpos;
10383  int backpos;
10384  int nvars;
10385  int pos;
10386  int k;
10387  int i;
10388 
10389  assert(nchgcoefs != NULL);
10390  assert(nchgsides != NULL);
10391  assert(!SCIPconsIsModifiable(cons));
10392 
10393  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10394  assert(conshdlrdata != NULL);
10395 
10396  consdata = SCIPconsGetData(cons);
10397  assert(consdata != NULL);
10398  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10399  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10400  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10401  assert(consdata->nvars > 0);
10402 
10403  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10404  if( *cutoff )
10405  return SCIP_OKAY;
10406 
10407  /* apply rule (1) */
10408  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10409  {
10410  do
10411  {
10412  assert(consdata->merged);
10413 
10414  /* sort items, s.t. the heaviest one is in the first position */
10415  sortItems(consdata);
10416 
10417  for( i = 0; i < consdata->nvars; ++i )
10418  {
10419  SCIP_Longint weight;
10420 
10421  weight = consdata->weights[i];
10422  if( consdata->weightsum - weight < consdata->capacity )
10423  {
10424  newweight = consdata->weightsum - consdata->capacity;
10425  consdataChgWeight(consdata, i, newweight);
10426  consdata->capacity -= (weight - newweight);
10427  (*nchgcoefs)++;
10428  (*nchgsides)++;
10429  assert(!consdata->sorted);
10430  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",
10431  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10432  consdata->capacity + (weight-newweight), consdata->capacity);
10433  }
10434  else
10435  break;
10436  }
10437  }
10438  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10439  }
10440 
10441  /* check for redundancy */
10442  if( consdata->weightsum <= consdata->capacity )
10443  return SCIP_OKAY;
10444 
10445  pos = 0;
10446  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10447  ++pos;
10448 
10449  sumcoef = 0;
10450  weights = consdata->weights;
10451  nvars = consdata->nvars;
10452  capacity = consdata->capacity;
10453 
10454  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10455  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10456  {
10457  /* further reductions using the next possible coefficient sum
10458  *
10459  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10460  */
10461  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10462  for( k = 0; k < 4; ++k )
10463  {
10464  newweight = capacity - sumcoef;
10465 
10466  /* determine next minimal coefficient sum */
10467  switch( k )
10468  {
10469  case 0:
10470  sumcoef = weights[nvars - 1];
10471  backpos = nvars - 1;
10472  break;
10473  case 1:
10474  sumcoef = weights[nvars - 2];
10475  backpos = nvars - 2;
10476  break;
10477  case 2:
10478  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10479  {
10480  sumcoefcase = TRUE;
10481  sumcoef = weights[nvars - 3];
10482  backpos = nvars - 3;
10483  }
10484  else
10485  {
10486  sumcoefcase = FALSE;
10487  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10488  backpos = nvars - 2;
10489  }
10490  break;
10491  default:
10492  assert(k == 3);
10493  if( sumcoefcase )
10494  {
10495  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10496  {
10497  sumcoef = weights[nvars - 4];
10498  backpos = nvars - 4;
10499  }
10500  else
10501  {
10502  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10503  backpos = nvars - 2;
10504  }
10505  }
10506  else
10507  {
10508  sumcoef = weights[nvars - 3];
10509  backpos = nvars - 3;
10510  }
10511  break;
10512  }
10513 
10514  if( backpos <= pos )
10515  break;
10516 
10517  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10518  maxweight = weights[pos];
10519  startpos = pos;
10520  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10521  {
10522  assert(newweight > weights[pos]);
10523 
10524  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10525  SCIPconsGetName(cons), maxweight, newweight);
10526 
10527  consdataChgWeight(consdata, pos, newweight);
10528 
10529  ++pos;
10530  assert(pos < nvars);
10531 
10532  maxweight = weights[pos];
10533 
10534  if( backpos <= pos )
10535  break;
10536  }
10537  (*nchgcoefs) += (pos - startpos);
10538 
10539  /* skip unchangable weights */
10540  while( pos < nvars && weights[pos] + sumcoef == capacity )
10541  ++pos;
10542 
10543  /* check special case were there is only one weight left to tighten
10544  *
10545  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10546  *
10547  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10548  *
10549  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10550  */
10551  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10552  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10553  {
10554  newweight = capacity - sumcoef;
10555  assert(newweight > weights[pos]);
10556 
10557  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10558  SCIPconsGetName(cons), maxweight, newweight);
10559 
10560  consdataChgWeight(consdata, pos, newweight);
10561 
10562  break;
10563  }
10564 
10565  if( backpos <= pos )
10566  break;
10567  }
10568  }
10569 
10570  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10571  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10572  {
10573  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10574  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10575  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10576  {
10577  SCIP_VAR** clqvars;
10578  SCIP_CONS* cliquecons;
10579  char name[SCIP_MAXSTRLEN];
10580  int* clqpart;
10581  int nclqvars;
10582  int nclq;
10583  int len;
10584  int c;
10585  int w;
10586 
10587  assert(!SCIPconsIsDeleted(cons));
10588 
10589  if( pos == consdata->nvars )
10590  {
10591  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10592 
10593  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10597  SCIPconsIsStickingAtNode(cons)) );
10598 
10599  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10600  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10601  ++(*naddconss);
10602 
10603  /* delete old constraint */
10604  SCIP_CALL( SCIPdelCons(scip, cons) );
10605  ++(*ndelconss);
10606 
10607  return SCIP_OKAY;
10608  }
10609 
10610  len = consdata->nvars - pos;
10611 
10612  /* allocate temporary memory */
10613  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10614 
10615  /* calculate clique partition */
10616  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10617  assert(nclq <= len);
10618 
10619 #ifndef NDEBUG
10620  /* clique numbers must be at least as high as the index */
10621  for( w = 0; w < nclq; ++w )
10622  assert(clqpart[w] <= w);
10623 #endif
10624 
10625  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10626 
10627  /* allocate temporary memory */
10628  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10629 
10630  /* copy corresponding variables with big coefficients */
10631  for( w = pos - 1; w >= 0; --w )
10632  clqvars[w] = consdata->vars[w];
10633 
10634  /* create for each clique a set-packing constraint */
10635  for( c = 0; c < nclq; ++c )
10636  {
10637  nclqvars = pos;
10638 
10639  for( w = c; w < len; ++w )
10640  {
10641  if( clqpart[w] == c )
10642  {
10643  assert(nclqvars < pos + len - nclq + 1);
10644  clqvars[nclqvars] = consdata->vars[w + pos];
10645  ++nclqvars;
10646  }
10647  }
10648 
10649  assert(nclqvars > 1);
10650 
10651  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10652  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10656  SCIPconsIsStickingAtNode(cons)) );
10657  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10658  SCIPdebugPrintCons(scip, cliquecons, NULL);
10659  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10660  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10661  ++(*naddconss);
10662  }
10663 
10664  /* delete old constraint */
10665  SCIP_CALL( SCIPdelCons(scip, cons) );
10666  ++(*ndelconss);
10667 
10668  SCIPfreeBufferArray(scip, &clqvars);
10669  SCIPfreeBufferArray(scip, &clqpart);
10670 
10671  return SCIP_OKAY;
10672  }
10673  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10674  {
10675  SCIP_Longint* maxcliqueweights;
10676  SCIP_Longint* newweightvals;
10677  int* newweightidxs;
10678  SCIP_Longint cliqueweightsum;
10679 
10680  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10681  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10682  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10683 
10684  /* repeat as long as changes have been applied */
10685  do
10686  {
10687  int ncliques;
10688  int cliquenum;
10689  SCIP_Bool zeroweights;
10690 
10691  assert(consdata->merged);
10692 
10693  /* sort items, s.t. the heaviest one is in the first position */
10694  sortItems(consdata);
10695 
10696  /* calculate a clique partition */
10697  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10698 
10699  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10700  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10701  break;
10702 
10703  /* calculate the maximal weight of the cliques and store the clique type */
10704  cliqueweightsum = 0;
10705  ncliques = 0;
10706 
10707  for( i = 0; i < consdata->nvars; ++i )
10708  {
10709  SCIP_Longint weight;
10710 
10711  cliquenum = consdata->cliquepartition[i];
10712  assert(0 <= cliquenum && cliquenum <= ncliques);
10713 
10714  weight = consdata->weights[i];
10715  assert(weight > 0);
10716 
10717  if( cliquenum == ncliques )
10718  {
10719  maxcliqueweights[ncliques] = weight;
10720  cliqueweightsum += weight;
10721  ++ncliques;
10722  }
10723 
10724  assert(maxcliqueweights[cliquenum] >= weight);
10725  }
10726 
10727  /* apply rule on every clique */
10728  zeroweights = FALSE;
10729  for( i = 0; i < ncliques; ++i )
10730  {
10731  SCIP_Longint delta;
10732 
10733  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10734  if( delta > 0 )
10735  {
10736  SCIP_Longint newcapacity;
10737 #ifndef NDEBUG
10738  SCIP_Longint newmincliqueweight;
10739 #endif
10740  SCIP_Longint newminweightsuminclique;
10741  SCIP_Bool forceclique;
10742  int nnewweights;
10743  int j;
10744 
10745  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",
10746  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10747  newcapacity = consdata->capacity - delta;
10748  forceclique = FALSE;
10749  nnewweights = 0;
10750 #ifndef NDEBUG
10751  newmincliqueweight = newcapacity + 1;
10752  for( j = 0; j < i; ++j )
10753  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10754 #endif
10755  for( j = i; j < consdata->nvars; ++j )
10756  {
10757  if( consdata->cliquepartition[j] == i )
10758  {
10759  newweight = consdata->weights[j] - delta;
10760  newweight = MAX(newweight, 0);
10761 
10762  /* cache the new weight */
10763  assert(nnewweights < consdata->nvars);
10764  newweightvals[nnewweights] = newweight;
10765  newweightidxs[nnewweights] = j;
10766  nnewweights++;
10767 
10768 #ifndef NDEBUG
10769  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10770  newmincliqueweight = newweight;
10771 #endif
10772  }
10773  }
10774 
10775  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10776  if( nnewweights > 1 )
10777  {
10778 #ifndef NDEBUG
10779  j = newweightidxs[nnewweights - 2];
10780  assert(0 <= j && j < consdata->nvars);
10781  assert(consdata->cliquepartition[j] == i);
10782  j = newweightidxs[nnewweights - 1];
10783  assert(0 <= j && j < consdata->nvars);
10784  assert(consdata->cliquepartition[j] == i);
10785 #endif
10786 
10787  newminweightsuminclique = newweightvals[nnewweights - 2];
10788  newminweightsuminclique += newweightvals[nnewweights - 1];
10789 
10790  /* check if these new two minimal weights both fit into the knapsack;
10791  * if this is true, we have to add a clique constraint in order to enforce the clique
10792  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10793  * reduction might be infeasible, i.e., allows additional solutions)
10794  */
10795  if( newminweightsuminclique <= newcapacity )
10796  forceclique = TRUE;
10797  }
10798 
10799  /* check if we really want to apply the change */
10800  if( conshdlrdata->disaggregation || !forceclique )
10801  {
10802  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10803  consdata->capacity, newcapacity, forceclique);
10804  consdata->capacity = newcapacity;
10805  (*nchgsides)++;
10806 
10807  for( k = 0; k < nnewweights; ++k )
10808  {
10809  j = newweightidxs[k];
10810  assert(0 <= j && j < consdata->nvars);
10811  assert(consdata->cliquepartition[j] == i);
10812 
10813  /* apply the weight change */
10814  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10815  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10816  consdataChgWeight(consdata, j, newweightvals[k]);
10817  (*nchgcoefs)++;
10818  assert(!consdata->sorted);
10819  zeroweights = zeroweights || (newweightvals[k] == 0);
10820  }
10821  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10822  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10823  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10824  * knapsack constraint
10825  */
10826  if( forceclique )
10827  {
10828  SCIP_CONS* cliquecons;
10829  char name[SCIP_MAXSTRLEN];
10830  SCIP_VAR** cliquevars;
10831 
10832  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10833  for( k = 0; k < nnewweights; ++k )
10834  cliquevars[k] = consdata->vars[newweightidxs[k]];
10835 
10836  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10837  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10841  SCIPconsIsStickingAtNode(cons)) );
10842  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10843  SCIPdebugPrintCons(scip, cliquecons, NULL);
10844  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10845  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10846  SCIPfreeBufferArray(scip, &cliquevars);
10847  (*naddconss)++;
10848  }
10849  }
10850  }
10851  }
10852  if( zeroweights )
10853  {
10854  SCIP_CALL( removeZeroWeights(scip, cons) );
10855  }
10856  }
10857  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10858 
10859  /* free temporary memory */
10860  SCIPfreeBufferArray(scip, &newweightidxs);
10861  SCIPfreeBufferArray(scip, &newweightvals);
10862  SCIPfreeBufferArray(scip, &maxcliqueweights);
10863 
10864  /* check for redundancy */
10865  if( consdata->weightsum <= consdata->capacity )
10866  return SCIP_OKAY;
10867  }
10868  }
10869 
10870  /* apply rule (3) */
10871  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10872  {
10873  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10874  }
10875 
10876  /* check for redundancy */
10877  if( consdata->weightsum <= consdata->capacity )
10878  return SCIP_OKAY;
10879 
10880  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10881  {
10882  /* apply rule (4) (all but smallest weight) */
10883  assert(consdata->merged);
10884  sortItems(consdata);
10885  minweight = consdata->weights[consdata->nvars-1];
10886  for( i = 0; i < consdata->nvars-1; ++i )
10887  {
10888  SCIP_Longint weight;
10889 
10890  weight = consdata->weights[i];
10891  assert(weight >= minweight);
10892  if( minweight + weight > consdata->capacity )
10893  {
10894  if( weight < consdata->capacity )
10895  {
10896  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10897  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10898  assert(consdata->sorted);
10899  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10900  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10901  consdata->sorted = TRUE;
10902  (*nchgcoefs)++;
10903  }
10904  }
10905  else
10906  break;
10907  }
10908 
10909  /* apply rule (5) (smallest weight) */
10910  if( consdata->nvars >= 2 )
10911  {
10912  SCIP_Longint weight;
10913 
10914  minweight = consdata->weights[consdata->nvars-2];
10915  weight = consdata->weights[consdata->nvars-1];
10916  assert(minweight >= weight);
10917  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10918  {
10919  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10920  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10921  assert(consdata->sorted);
10922  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10923  assert(minweight >= consdata->weights[consdata->nvars-1]);
10924  consdata->sorted = TRUE;
10925  (*nchgcoefs)++;
10926  }
10927  }
10928  }
10929 
10930  return SCIP_OKAY;
10931 }
10932 
10933 
10934 #ifdef SCIP_DEBUG
10935 static
10936 void printClique(
10937  SCIP_VAR** cliquevars,
10938  int ncliquevars
10939  )
10940 {
10941  int b;
10942  SCIPdebugMessage("adding new Clique: ");
10943  for( b = 0; b < ncliquevars; ++b )
10944  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10945  SCIPdebugPrintf("\n");
10946 }
10947 #endif
10948 
10949 /** adds negated cliques of the knapsack constraint to the global clique table */
10950 static
10952  SCIP*const scip, /**< SCIP data structure */
10953  SCIP_CONS*const cons, /**< knapsack constraint */
10954  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10955  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10956  )
10957 {
10958  SCIP_CONSDATA* consdata;
10959  SCIP_CONSHDLRDATA* conshdlrdata;
10960  SCIP_VAR** poscliquevars;
10961  SCIP_VAR** cliquevars;
10962  SCIP_Longint* maxweights;
10963  SCIP_Longint* gainweights;
10964  int* gaincliquepartition;
10965  SCIP_Bool* cliqueused;
10966  SCIP_Longint minactduetonegcliques;
10967  SCIP_Longint freecapacity;
10968  SCIP_Longint lastweight;
10969  SCIP_Longint beforelastweight;
10970  int nposcliquevars;
10971  int ncliquevars;
10972  int nvars;
10973  int nnegcliques;
10974  int lastcliqueused;
10975  int thisnbdchgs;
10976  int v;
10977  int w;
10978 
10979  assert(scip != NULL);
10980  assert(cons != NULL);
10981  assert(cutoff != NULL);
10982  assert(nbdchgs != NULL);
10983 
10984  *cutoff = FALSE;
10985 
10986  consdata = SCIPconsGetData(cons);
10987  assert(consdata != NULL);
10988 
10989  nvars = consdata->nvars;
10990 
10991  /* check whether the cliques have already been added */
10992  if( consdata->cliquesadded || nvars == 0 )
10993  return SCIP_OKAY;
10994 
10995  /* make sure, the items are merged */
10996  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10997  if( *cutoff )
10998  return SCIP_OKAY;
10999 
11000  /* make sure, items are sorted by non-increasing weight */
11001  sortItems(consdata);
11002 
11003  assert(consdata->merged);
11004 
11005  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11006  assert(conshdlrdata != NULL);
11007 
11008  /* calculate a clique partition */
11009  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11010  nnegcliques = consdata->nnegcliques;
11011 
11012  /* if we have no negated cliques, stop */
11013  if( nnegcliques == nvars )
11014  return SCIP_OKAY;
11015 
11016  /* get temporary memory */
11017  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11018  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11019  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11020  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11021  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11022  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11023 
11024  nnegcliques = 0;
11025  minactduetonegcliques = 0;
11026 
11027  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11028  for( v = 0; v < nvars; ++v )
11029  {
11030  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11031  assert(consdata->weights[v] > 0);
11032 
11033  if( consdata->negcliquepartition[v] == nnegcliques )
11034  {
11035  nnegcliques++;
11036  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11037  }
11038  else
11039  minactduetonegcliques += consdata->weights[v];
11040  }
11041 
11042  nposcliquevars = 0;
11043 
11044  /* add cliques, using negated cliques information */
11045  if( minactduetonegcliques > 0 )
11046  {
11047  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11048  freecapacity = consdata->capacity - minactduetonegcliques;
11049 
11050  SCIPdebugPrintCons(scip, cons, NULL);
11051  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",
11052  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11053 
11054  /* calculate possible gain by switching chosen items in negated cliques */
11055  for( v = 0; v < nvars; ++v )
11056  {
11057  if( !cliqueused[consdata->negcliquepartition[v]] )
11058  {
11059  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11060  for( w = v + 1; w < nvars; ++w )
11061  {
11062  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11063  * weight[w] (which are both in a negated clique) */
11064  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11065  && consdata->weights[v] > consdata->weights[w] )
11066  {
11067  poscliquevars[nposcliquevars] = consdata->vars[w];
11068  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11069  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11070  ++nposcliquevars;
11071  }
11072  }
11073  }
11074  }
11075 
11076  /* try to create negated cliques */
11077  if( nposcliquevars > 0 )
11078  {
11079  /* sort possible gain per substitution of the clique members */
11080  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11081 
11082  for( v = 0; v < nposcliquevars; ++v )
11083  {
11084  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11085  ncliquevars = 1;
11086  lastweight = gainweights[v];
11087  beforelastweight = -1;
11088  lastcliqueused = gaincliquepartition[v];
11089  /* clear cliqueused to get an unused array */
11090  BMSclearMemoryArray(cliqueused, nnegcliques);
11091  cliqueused[gaincliquepartition[v]] = TRUE;
11092 
11093  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11094  * in the same negated clique and by taking two of them would exceed the free capacity */
11095  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11096  {
11097  beforelastweight = lastweight;
11098  lastweight = gainweights[w];
11099  lastcliqueused = gaincliquepartition[w];
11100  cliqueused[gaincliquepartition[w]] = TRUE;
11101  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11102  ++ncliquevars;
11103  }
11104 
11105  if( ncliquevars > 1 )
11106  {
11107  SCIPdebug( printClique(cliquevars, ncliquevars) );
11108  assert(beforelastweight > 0);
11109  /* add the clique to the clique table */
11110  /* this really happens, e.g., on enigma.mps from the short test set */
11111  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11112  if( *cutoff )
11113  goto TERMINATE;
11114  *nbdchgs += thisnbdchgs;
11115 
11116  /* reset last used clique to get slightly different cliques */
11117  cliqueused[lastcliqueused] = FALSE;
11118 
11119  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11120  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11121  {
11122  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11123  SCIPdebug( printClique(cliquevars, ncliquevars) );
11124  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11125  if( *cutoff )
11126  goto TERMINATE;
11127  *nbdchgs += thisnbdchgs;
11128  }
11129  }
11130  }
11131  }
11132  }
11133 
11134  TERMINATE:
11135  /* free temporary memory */
11136  SCIPfreeBufferArray(scip, &cliqueused);
11137  SCIPfreeBufferArray(scip, &maxweights);
11138  SCIPfreeBufferArray(scip, &gaincliquepartition);
11139  SCIPfreeBufferArray(scip, &gainweights);
11140  SCIPfreeBufferArray(scip, &cliquevars);
11141  SCIPfreeBufferArray(scip, &poscliquevars);
11142 
11143  return SCIP_OKAY;
11144 }
11145 
11146 /** greedy clique detection by considering weights and capacity
11147  *
11148  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11149  * 1) neighboring items which exceed the capacity together => one clique
11150  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11151  */
11152 static
11154  SCIP*const scip, /**< SCIP data structure */
11155  SCIP_VAR** items, /**< array of variable items */
11156  SCIP_Longint* weights, /**< weights of the items */
11157  int nitems, /**< the number of items */
11158  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11159  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11160  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11161  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11162  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11163  )
11164 {
11165  SCIP_Longint lastweight;
11166  int ncliquevars;
11167  int i;
11168  int thisnbdchgs;
11169 
11170  if( nitems <= 1 )
11171  return SCIP_OKAY;
11172 
11173  /* sort possible gain per substitution of the clique members */
11174  if( ! sorteditems )
11175  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11176 
11177  ncliquevars = 1;
11178  lastweight = weights[0];
11179 
11180  /* taking these two weights together violates the knapsack => include into clique */
11181  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11182  {
11183  lastweight = weights[i];
11184  ++ncliquevars;
11185  }
11186 
11187  if( ncliquevars > 1 )
11188  {
11189  SCIP_Longint compareweight;
11190  SCIP_VAR** cliquevars;
11191  int compareweightidx;
11192  int minclqsize;
11193  int nnzadded;
11194 
11195  /* add the clique to the clique table */
11196  SCIPdebug( printClique(items, ncliquevars) );
11197  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11198 
11199  if( *cutoff )
11200  return SCIP_OKAY;
11201 
11202  *nbdchgs += thisnbdchgs;
11203  nnzadded = ncliquevars;
11204 
11205  /* 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)*/
11206  if( ncliquevars == nitems )
11207  return SCIP_OKAY;
11208 
11209  /* copy items in order into buffer array and deduce more cliques */
11210  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11211 
11212  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11213  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11214  compareweightidx = ncliquevars - 2;
11215  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11216 
11217  /* determine minimum clique size for the following loop */
11218  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11219  minclqsize = MAX(minclqsize, 2);
11220 
11221  /* loop over the remaining variables and the larger items of the first clique until we
11222  * find another clique or reach the size limit */
11223  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11224  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11225  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11226  )
11227  {
11228  compareweight = weights[compareweightidx];
11229  assert(compareweight > 0);
11230 
11231  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11232  if( compareweight + weights[i] > capacity )
11233  {
11234  assert(compareweightidx == ncliquevars -2);
11235  cliquevars[ncliquevars - 1] = items[i];
11236  SCIPdebug( printClique(cliquevars, ncliquevars) );
11237  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11238 
11239  nnzadded += ncliquevars;
11240 
11241  /* stop when there is a cutoff */
11242  if( ! (*cutoff) )
11243  *nbdchgs += thisnbdchgs;
11244 
11245  /* go to next smaller item */
11246  ++i;
11247  }
11248  else
11249  {
11250  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11251  compareweightidx--;
11252  ncliquevars --;
11253  }
11254  }
11255 
11256  SCIPfreeBufferArray(scip, &cliquevars);
11257  }
11258 
11259  return SCIP_OKAY;
11260 }
11261 
11262 /** adds cliques of the knapsack constraint to the global clique table */
11263 static
11265  SCIP*const scip, /**< SCIP data structure */
11266  SCIP_CONS*const cons, /**< knapsack constraint */
11267  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11268  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11269  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11270  )
11271 {
11272  SCIP_CONSDATA* consdata;
11273  SCIP_CONSHDLRDATA* conshdlrdata;
11274  int i;
11275  SCIP_Longint minactduetonegcliques;
11276  SCIP_Longint freecapacity;
11277  int nnegcliques;
11278  int cliquenum;
11279  SCIP_VAR** poscliquevars;
11280  SCIP_Longint* gainweights;
11281  int nposcliquevars;
11282  SCIP_Longint* secondmaxweights;
11283  int nvars;
11284 
11285  assert(scip != NULL);
11286  assert(cons != NULL);
11287  assert(cutoff != NULL);
11288  assert(nbdchgs != NULL);
11289 
11290  *cutoff = FALSE;
11291 
11292  consdata = SCIPconsGetData(cons);
11293  assert(consdata != NULL);
11294 
11295  nvars = consdata->nvars;
11296 
11297  /* check whether the cliques have already been added */
11298  if( consdata->cliquesadded || nvars == 0 )
11299  return SCIP_OKAY;
11300 
11301  /* make sure, the items are merged */
11302  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11303  if( *cutoff )
11304  return SCIP_OKAY;
11305 
11306  /* make sure, the items are sorted by non-increasing weight */
11307  sortItems(consdata);
11308 
11309  assert(consdata->merged);
11310 
11311  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11312  assert(conshdlrdata != NULL);
11313 
11314  /* calculate a clique partition */
11315  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11316  nnegcliques = consdata->nnegcliques;
11317  assert(nnegcliques <= nvars);
11318 
11319  /* get temporary memory */
11320  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11321  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11322  BMSclearMemoryArray(gainweights, nvars);
11323  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11324  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11325 
11326  minactduetonegcliques = 0;
11327 
11328  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11329  if( nnegcliques < nvars )
11330  {
11331  nnegcliques = 0;
11332 
11333  for( i = 0; i < nvars; ++i )
11334  {
11335  SCIP_Longint weight;
11336 
11337  cliquenum = consdata->negcliquepartition[i];
11338  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11339 
11340  weight = consdata->weights[i];
11341  assert(weight > 0);
11342 
11343  if( cliquenum == nnegcliques )
11344  nnegcliques++;
11345  else
11346  {
11347  minactduetonegcliques += weight;
11348  if( secondmaxweights[cliquenum] == 0 )
11349  secondmaxweights[cliquenum] = weight;
11350  }
11351  }
11352  }
11353 
11354  /* add cliques, using negated cliques information */
11355  if( minactduetonegcliques > 0 )
11356  {
11357  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11358  freecapacity = consdata->capacity - minactduetonegcliques;
11359 
11360  SCIPdebugPrintCons(scip, cons, NULL);
11361  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",
11362  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11363 
11364  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11365  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11366 
11367  if( *cutoff )
11368  goto TERMINATE;
11369 
11370  nposcliquevars = 0;
11371 
11372  for( i = nvars - 1; i >= 0; --i )
11373  {
11374  /* if we would take the biggest weight instead of the second biggest */
11375  cliquenum = consdata->negcliquepartition[i];
11376  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11377  {
11378  poscliquevars[nposcliquevars] = consdata->vars[i];
11379  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11380  ++nposcliquevars;
11381  }
11382  }
11383 
11384  /* use the gain weights and free capacity to derive greedily cliques */
11385  if( nposcliquevars > 1 )
11386  {
11387  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11388 
11389  if( *cutoff )
11390  goto TERMINATE;
11391  }
11392  }
11393 
11394  /* build cliques by using the items with the maximal weights */
11395  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11396 
11397  TERMINATE:
11398  /* free temporary memory and mark the constraint */
11399  SCIPfreeBufferArray(scip, &secondmaxweights);
11400  SCIPfreeBufferArray(scip, &gainweights);
11401  SCIPfreeBufferArray(scip, &poscliquevars);
11402  consdata->cliquesadded = TRUE;
11403 
11404  return SCIP_OKAY;
11405 }
11406 
11407 
11408 /** gets the key of the given element */
11409 static
11410 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11411 { /*lint --e{715}*/
11412  /* the key is the element itself */
11413  return elem;
11414 }
11415 
11416 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11417  * same coefficients
11418  */
11419 static
11420 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11421 {
11422 #ifndef NDEBUG
11423  SCIP* scip;
11424 #endif
11425  SCIP_CONSDATA* consdata1;
11426  SCIP_CONSDATA* consdata2;
11427  int i;
11429  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11430  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11431  assert(consdata1->sorted);
11432  assert(consdata2->sorted);
11433 #ifndef NDEBUG
11434  scip = (SCIP*)userptr;
11435  assert(scip != NULL);
11436 #endif
11437 
11438  /* checks trivial case */
11439  if( consdata1->nvars != consdata2->nvars )
11440  return FALSE;
11441 
11442  for( i = consdata1->nvars - 1; i >= 0; --i )
11443  {
11444  /* tests if variables are equal */
11445  if( consdata1->vars[i] != consdata2->vars[i] )
11446  {
11447  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11448  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11449  return FALSE;
11450  }
11451  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11452 
11453  /* tests if weights are equal too */
11454  if( consdata1->weights[i] != consdata2->weights[i] )
11455  return FALSE;
11456  }
11457 
11458  return TRUE;
11459 }
11460 
11461 /** returns the hash value of the key */
11462 static
11463 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11464 {
11465 #ifndef NDEBUG
11466  SCIP* scip;
11467 #endif
11468  SCIP_CONSDATA* consdata;
11469  uint64_t firstweight;
11470  int minidx;
11471  int mididx;
11472  int maxidx;
11473 
11474  consdata = SCIPconsGetData((SCIP_CONS*)key);
11475  assert(consdata != NULL);
11476  assert(consdata->nvars > 0);
11477 
11478 #ifndef NDEBUG
11479  scip = (SCIP*)userptr;
11480  assert(scip != NULL);
11481 #endif
11482 
11483  /* sorts the constraints */
11484  sortItems(consdata);
11485 
11486  minidx = SCIPvarGetIndex(consdata->vars[0]);
11487  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11488  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11489  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11490 
11491  /* hash value depends on vectors of variable indices */
11492  firstweight = (uint64_t)consdata->weights[0];
11493  return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11494 }
11495 
11496 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11497  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11498  */
11499 static
11501  SCIP* scip, /**< SCIP data structure */
11502  BMS_BLKMEM* blkmem, /**< block memory */
11503  SCIP_CONS** conss, /**< constraint set */
11504  int nconss, /**< number of constraints in constraint set */
11505  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11506  int* ndelconss /**< pointer to count number of deleted constraints */
11507  )
11509  SCIP_HASHTABLE* hashtable;
11510  int hashtablesize;
11511  int c;
11512 
11513  assert(scip != NULL);
11514  assert(blkmem != NULL);
11515  assert(conss != NULL);
11516  assert(ndelconss != NULL);
11517 
11518  /* create a hash table for the constraint set */
11519  hashtablesize = nconss;
11520  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11521  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11522  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11523 
11524  /* check all constraints in the given set for redundancy */
11525  for( c = nconss - 1; c >= 0; --c )
11526  {
11527  SCIP_CONS* cons0;
11528  SCIP_CONS* cons1;
11529  SCIP_CONSDATA* consdata0;
11530 
11531  cons0 = conss[c];
11532 
11533  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11534  continue;
11535 
11536  consdata0 = SCIPconsGetData(cons0);
11537  assert(consdata0 != NULL);
11538  if( consdata0->nvars == 0 )
11539  {
11540  if( consdata0->capacity < 0 )
11541  {
11542  *cutoff = TRUE;
11543  goto TERMINATE;
11544  }
11545  else
11546  {
11547  SCIP_CALL( SCIPdelCons(scip, cons0) );
11548  ++(*ndelconss);
11549  continue;
11550  }
11551  }
11552 
11553  /* get constraint from current hash table with same variables and same weights as cons0 */
11554  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11555 
11556  if( cons1 != NULL )
11557  {
11558  SCIP_CONS* consstay;
11559  SCIP_CONS* consdel;
11560  SCIP_CONSDATA* consdata1;
11561 
11562  assert(SCIPconsIsActive(cons1));
11563  assert(!SCIPconsIsModifiable(cons1));
11564 
11565  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11566  * delete old constraints afterwards
11567  */
11568  consdata1 = SCIPconsGetData(cons1);
11569 
11570  assert(consdata1 != NULL);
11571  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11572 
11573  assert(consdata0->sorted && consdata1->sorted);
11574  assert(consdata0->vars[0] == consdata1->vars[0]);
11575  assert(consdata0->weights[0] == consdata1->weights[0]);
11576 
11577  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11578  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11579 
11580  /* check which constraint has to stay; */
11581  if( consdata0->capacity < consdata1->capacity )
11582  {
11583  consstay = cons0;
11584  consdel = cons1;
11585 
11586  /* exchange consdel with consstay in hashtable */
11587  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11588  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11589  }
11590  else
11591  {
11592  consstay = cons1;
11593  consdel = cons0;
11594  }
11595 
11596  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11597  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11598 
11599  /* delete consdel */
11600  SCIP_CALL( SCIPdelCons(scip, consdel) );
11601  ++(*ndelconss);
11602 
11603  assert(SCIPconsIsActive(consstay));
11604  }
11605  else
11606  {
11607  /* no such constraint in current hash table: insert cons0 into hash table */
11608  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11609  }
11610  }
11611 
11612  TERMINATE:
11613  /* free hash table */
11614  SCIPhashtableFree(&hashtable);
11615 
11616  return SCIP_OKAY;
11617 }
11618 
11619 
11620 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11621  * and removes or changes constraint accordingly
11622  */
11623 static
11625  SCIP* scip, /**< SCIP data structure */
11626  SCIP_CONS** conss, /**< constraint set */
11627  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11628  int chkind, /**< index of constraint to check against all prior indices upto startind */
11629  int* ndelconss /**< pointer to count number of deleted constraints */
11630  )
11631 {
11632  SCIP_CONS* cons0;
11633  SCIP_CONSDATA* consdata0;
11634  int c;
11635 
11636  assert(scip != NULL);
11637  assert(conss != NULL);
11638  assert(firstchange <= chkind);
11639  assert(ndelconss != NULL);
11640 
11641  /* get the constraint to be checked against all prior constraints */
11642  cons0 = conss[chkind];
11643  assert(cons0 != NULL);
11644  assert(SCIPconsIsActive(cons0));
11645  assert(!SCIPconsIsModifiable(cons0));
11646 
11647  consdata0 = SCIPconsGetData(cons0);
11648  assert(consdata0 != NULL);
11649  assert(consdata0->nvars >= 1);
11650  assert(consdata0->merged);
11651 
11652  /* sort the constraint */
11653  sortItems(consdata0);
11654 
11655  /* see #2970 */
11656  if( consdata0->capacity == 0 )
11657  return SCIP_OKAY;
11658 
11659  /* check constraint against all prior constraints */
11660  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11661  {
11662  SCIP_CONS* cons1;
11663  SCIP_CONSDATA* consdata1;
11664  SCIP_Bool iscons0incons1contained;
11665  SCIP_Bool iscons1incons0contained;
11666  SCIP_Real quotient;
11667  int v;
11668  int v0;
11669  int v1;
11670 
11671  cons1 = conss[c];
11672  assert(cons1 != NULL);
11673  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11674  continue;
11675 
11676  consdata1 = SCIPconsGetData(cons1);
11677  assert(consdata1 != NULL);
11678 
11679  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11680  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11681  continue;
11682 
11683  assert(consdata1->nvars >= 1);
11684  assert(consdata1->merged);
11685 
11686  /* sort the constraint */
11687  sortItems(consdata1);
11688 
11689  /* see #2970 */
11690  if( consdata1->capacity == 0 )
11691  continue;
11692 
11693  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11694 
11695  if( consdata0->nvars > consdata1->nvars )
11696  {
11697  iscons0incons1contained = FALSE;
11698  iscons1incons0contained = TRUE;
11699  v = consdata1->nvars - 1;
11700  }
11701  else if( consdata0->nvars < consdata1->nvars )
11702  {
11703  iscons0incons1contained = TRUE;
11704  iscons1incons0contained = FALSE;
11705  v = consdata0->nvars - 1;
11706  }
11707  else
11708  {
11709  iscons0incons1contained = TRUE;
11710  iscons1incons0contained = TRUE;
11711  v = consdata0->nvars - 1;
11712  }
11713 
11714  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11715 
11716  /* check consdata0 against consdata1:
11717  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11718  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11719  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11720  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11721  */
11722  v0 = consdata0->nvars - 1;
11723  v1 = consdata1->nvars - 1;
11724 
11725  while( v >= 0 )
11726  {
11727  assert(iscons0incons1contained || iscons1incons0contained);
11728 
11729  /* now there are more variables in cons1 left */
11730  if( v1 > v0 )
11731  {
11732  iscons1incons0contained = FALSE;
11733  if( !iscons0incons1contained )
11734  break;
11735  }
11736  /* now there are more variables in cons0 left */
11737  else if( v1 < v0 )
11738  {
11739  iscons0incons1contained = FALSE;
11740  if( !iscons1incons0contained )
11741  break;
11742  }
11743 
11744  assert(v == v0 || v == v1);
11745  assert(v0 >= 0);
11746  assert(v1 >= 0);
11747 
11748  /* both variables are the same */
11749  if( consdata0->vars[v0] == consdata1->vars[v1] )
11750  {
11751  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11752  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11753  {
11754  iscons1incons0contained = FALSE;
11755  if( !iscons0incons1contained )
11756  break;
11757  }
11758  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11759  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11760  {
11761  iscons0incons1contained = FALSE;
11762  if( !iscons1incons0contained )
11763  break;
11764  }
11765  --v0;
11766  --v1;
11767  --v;
11768  }
11769  else
11770  {
11771  /* both constraints have a variables which is not part of the other constraint, so stop */
11772  if( iscons0incons1contained && iscons1incons0contained )
11773  {
11774  iscons0incons1contained = FALSE;
11775  iscons1incons0contained = FALSE;
11776  break;
11777  }
11778  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11779  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11780  /* continue to the next variable */
11781  if( iscons0incons1contained )
11782  --v1;
11783  else
11784  --v0;
11785  }
11786  }
11787  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11788  * other
11789  */
11790  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11791 
11792  if( iscons1incons0contained )
11793  {
11794  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11795  SCIPdebugPrintCons(scip, cons1, NULL);
11796 
11797  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11798  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11799 
11800  SCIP_CALL( SCIPdelCons(scip, cons1) );
11801  ++(*ndelconss);
11802  }
11803  else if( iscons0incons1contained )
11804  {
11805  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11806  SCIPdebugPrintCons(scip, cons0, NULL);
11807 
11808  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11809  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11810 
11811  SCIP_CALL( SCIPdelCons(scip, cons0) );
11812  ++(*ndelconss);
11813  break;
11814  }
11815  }
11816 
11817  return SCIP_OKAY;
11818 }
11819 
11820 /** helper function to enforce constraints */
11821 static
11823  SCIP* scip, /**< SCIP data structure */
11824  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11825  SCIP_CONS** conss, /**< constraints to process */
11826  int nconss, /**< number of constraints */
11827  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11828  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11829  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11830  )
11831 {
11832  SCIP_CONSHDLRDATA* conshdlrdata;
11833  SCIP_Bool violated;
11834  SCIP_Bool cutoff = FALSE;
11835  int maxncuts;
11836  int ncuts = 0;
11837  int i;
11838 
11839  *result = SCIP_FEASIBLE;
11840 
11841  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11842  sol == NULL ? "LP" : "relaxation");
11843 
11844  /* get maximal number of cuts per round */
11845  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11846  assert(conshdlrdata != NULL);
11847  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11848 
11849  /* search for violated useful knapsack constraints */
11850  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11851  {
11852  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11853  if( violated )
11854  {
11855  /* add knapsack constraint as LP row to the relaxation */
11856  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11857  ncuts++;
11858  }
11859  }
11860 
11861  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11862  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11863  {
11864  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11865  if( violated )
11866  {
11867  /* add knapsack constraint as LP row to the relaxation */
11868  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11869  ncuts++;
11870  }
11871  }
11872 
11873  /* adjust the result code */
11874  if ( cutoff )
11875  *result = SCIP_CUTOFF;
11876  else if ( ncuts > 0 )
11877  *result = SCIP_SEPARATED;
11878 
11879  return SCIP_OKAY;
11880 }
11881 
11882 /*
11883  * Linear constraint upgrading
11884  */
11885 
11886 /** creates and captures a knapsack constraint out of a linear inequality */
11887 static
11889  SCIP* scip, /**< SCIP data structure */
11890  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11891  const char* name, /**< name of constraint */
11892  int nvars, /**< number of variables in the constraint */
11893  SCIP_VAR** vars, /**< array with variables of constraint entries */
11894  SCIP_Real* vals, /**< array with inequality coefficients */
11895  SCIP_Real lhs, /**< left hand side of inequality */
11896  SCIP_Real rhs, /**< right hand side of inequality */
11897  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11898  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11899  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11900  * Usually set to TRUE. */
11901  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11902  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11903  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11904  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11905  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11906  * Usually set to TRUE. */
11907  SCIP_Bool local, /**< is constraint only valid locally?
11908  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11909  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11910  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11911  * adds coefficients to this constraint. */
11912  SCIP_Bool dynamic, /**< is constraint subject to aging?
11913  * Usually set to FALSE. Set to TRUE for own cuts which
11914  * are separated as constraints. */
11915  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11916  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11917  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11918  * if it may be moved to a more global node?
11919  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11920  )
11921 {
11922  SCIP_VAR** transvars;
11923  SCIP_Longint* weights;
11924  SCIP_Longint capacity;
11925  SCIP_Longint weight;
11926  int mult;
11927  int v;
11928 
11929  assert(nvars == 0 || vars != NULL);
11930  assert(nvars == 0 || vals != NULL);
11931  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11932 
11933  /* get temporary memory */
11934  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11935  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11936 
11937  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11938  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11939  */
11940  if( SCIPisInfinity(scip, rhs) )
11941  {
11942  mult = -1;
11943  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11944  }
11945  else
11946  {
11947  mult = +1;
11948  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11949  }
11950 
11951  /* negate positive or negative variables */
11952  for( v = 0; v < nvars; ++v )
11953  {
11954  assert(SCIPisFeasIntegral(scip, vals[v]));
11955  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11956  if( weight > 0 )
11957  {
11958  transvars[v] = vars[v];
11959  weights[v] = weight;
11960  }
11961  else
11962  {
11963  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11964  weights[v] = -weight; /*lint !e2704*/
11965  capacity -= weight;
11966  }
11967  assert(transvars[v] != NULL);
11968  }
11969 
11970  /* create the constraint */
11971  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11972  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11973 
11974  /* free temporary memory */
11975  SCIPfreeBufferArray(scip, &weights);
11976  SCIPfreeBufferArray(scip, &transvars);
11977 
11978  return SCIP_OKAY;
11979 }
11980 
11981 /** tries to upgrade a linear constraint into a knapsack constraint */
11982 static
11983 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11984 { /*lint --e{715}*/
11985  SCIP_Bool upgrade;
11986 
11987  assert(upgdcons != NULL);
11988 
11989  /* check, if linear constraint can be upgraded to a knapsack constraint
11990  * - all variables must be binary
11991  * - all coefficients must be integral
11992  * - exactly one of the sides must be infinite
11993  * note that this includes the case of negative capacity, which has been
11994  * observed to occur, e.g., when upgrading a conflict constraint
11995  */
11996  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11997  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11998  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11999 
12000  if( upgrade )
12001  {
12002  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12003 
12004  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12005  assert(!SCIPconsIsModifiable(cons));
12006  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12011  }
12012 
12013  return SCIP_OKAY;
12014 }
12015 
12016 
12017 /*
12018  * Callback methods of constraint handler
12019  */
12020 
12021 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12022 /**! [SnippetConsCopyKnapsack] */
12023 static
12024 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12025 { /*lint --e{715}*/
12026  assert(scip != NULL);
12027  assert(conshdlr != NULL);
12028  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12029 
12030  /* call inclusion method of constraint handler */
12033  *valid = TRUE;
12034 
12035  return SCIP_OKAY;
12036 }
12037 /**! [SnippetConsCopyKnapsack] */
12038 
12039 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12040 /**! [SnippetConsFreeKnapsack] */
12041 static
12042 SCIP_DECL_CONSFREE(consFreeKnapsack)
12043 { /*lint --e{715}*/
12044  SCIP_CONSHDLRDATA* conshdlrdata;
12045 
12046  /* free constraint handler data */
12047  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12048  assert(conshdlrdata != NULL);
12049 
12050  SCIPfreeBlockMemory(scip, &conshdlrdata);
12051 
12052  SCIPconshdlrSetData(conshdlr, NULL);
12053 
12054  return SCIP_OKAY;
12055 }
12056 /**! [SnippetConsFreeKnapsack] */
12057 
12058 
12059 /** initialization method of constraint handler (called after problem was transformed) */
12060 static
12061 SCIP_DECL_CONSINIT(consInitKnapsack)
12062 { /*lint --e{715}*/
12063  SCIP_CONSHDLRDATA* conshdlrdata;
12064  int nvars;
12065 
12066  assert( scip != NULL );
12067  assert( conshdlr != NULL );
12068 
12069  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12070  assert(conshdlrdata != NULL);
12071 
12072  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12073  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12074 
12075  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12076  conshdlrdata->reals1size = nvars;
12077 
12078  return SCIP_OKAY;
12079 }
12080 
12081 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12082 static
12083 SCIP_DECL_CONSEXIT(consExitKnapsack)
12084 { /*lint --e{715}*/
12085  SCIP_CONSHDLRDATA* conshdlrdata;
12086 
12087  assert( scip != NULL );
12088  assert( conshdlr != NULL );
12089 
12090  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12091  assert(conshdlrdata != NULL);
12092 
12093  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12094  conshdlrdata->reals1size = 0;
12095 
12096  return SCIP_OKAY;
12097 }
12098 
12099 
12100 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12101 static
12102 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12103 { /*lint --e{715}*/
12104  SCIP_CONSHDLRDATA* conshdlrdata;
12105  int nvars;
12106 
12107  assert(scip != NULL);
12108  assert(conshdlr != NULL);
12109  assert(nconss == 0 || conss != NULL);
12111  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12112  assert(conshdlrdata != NULL);
12113 
12114  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12115  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12116 
12117  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12118  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12119  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12120  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12121  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12122  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12123  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12124  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12125 
12126  conshdlrdata->ints1size = nvars;
12127  conshdlrdata->ints2size = nvars;
12128  conshdlrdata->longints1size = nvars;
12129  conshdlrdata->longints2size = nvars;
12130  conshdlrdata->bools1size = nvars;
12131  conshdlrdata->bools2size = nvars;
12132  conshdlrdata->bools3size = nvars;
12133  conshdlrdata->bools4size = nvars;
12134 
12135 #ifdef WITH_CARDINALITY_UPGRADE
12136  conshdlrdata->upgradedcard = FALSE;
12137 #endif
12138 
12139  return SCIP_OKAY;
12140 }
12141 
12142 
12143 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12144 static
12145 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12146 { /*lint --e{715}*/
12147  SCIP_CONSHDLRDATA* conshdlrdata;
12148  int c;
12149 
12150  assert(scip != NULL);
12151  assert(conshdlr != NULL);
12152 
12153  for( c = 0; c < nconss; ++c )
12154  {
12155  if( !SCIPconsIsDeleted(conss[c]) )
12156  {
12157  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12158  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12159  }
12160  }
12161 
12162  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12163  assert(conshdlrdata != NULL);
12164 
12165  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12166  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12167  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12168  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12169  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12170  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12171  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12172  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12173 
12174  conshdlrdata->ints1size = 0;
12175  conshdlrdata->ints2size = 0;
12176  conshdlrdata->longints1size = 0;
12177  conshdlrdata->longints2size = 0;
12178  conshdlrdata->bools1size = 0;
12179  conshdlrdata->bools2size = 0;
12180  conshdlrdata->bools3size = 0;
12181  conshdlrdata->bools4size = 0;
12182 
12183  return SCIP_OKAY;
12184 }
12185 
12186 /** solving process initialization method of constraint handler */
12187 static
12188 SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12189 { /*lint --e{715}*/
12190  /* add nlrow representation to NLP, if NLP had been constructed */
12191  if( SCIPisNLPConstructed(scip) )
12192  {
12193  int c;
12194  for( c = 0; c < nconss; ++c )
12195  {
12196  SCIP_CALL( addNlrow(scip, conss[c]) );
12197  }
12198  }
12199 
12200  return SCIP_OKAY;
12201 }
12202 
12203 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12204 static
12205 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12206 { /*lint --e{715}*/
12207  SCIP_CONSDATA* consdata;
12208  int c;
12209 
12210  assert( scip != NULL );
12211 
12212  /* release the rows and nlrows of all constraints */
12213  for( c = 0; c < nconss; ++c )
12214  {
12215  consdata = SCIPconsGetData(conss[c]);
12216  assert(consdata != NULL);
12217 
12218  if( consdata->row != NULL )
12219  {
12220  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12221  }
12222 
12223  if( consdata->nlrow != NULL )
12224  {
12225  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12226  }
12227  }
12228 
12229  return SCIP_OKAY;
12230 }
12231 
12232 /** frees specific constraint data */
12233 static
12234 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12235 { /*lint --e{715}*/
12236  SCIP_CONSHDLRDATA* conshdlrdata;
12237 
12238  assert(conshdlr != NULL);
12239  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12240 
12241  /* get event handler */
12242  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12243  assert(conshdlrdata != NULL);
12244  assert(conshdlrdata->eventhdlr != NULL);
12245 
12246  /* free knapsack constraint */
12247  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12248 
12249  return SCIP_OKAY;
12250 }
12251 
12252 /** transforms constraint data into data belonging to the transformed problem */
12253 /**! [SnippetConsTransKnapsack]*/
12254 static
12255 SCIP_DECL_CONSTRANS(consTransKnapsack)
12256 { /*lint --e{715}*/
12257  SCIP_CONSHDLRDATA* conshdlrdata;
12258  SCIP_CONSDATA* sourcedata;
12259  SCIP_CONSDATA* targetdata;
12260 
12261  assert(conshdlr != NULL);
12262  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12264  assert(sourcecons != NULL);
12265  assert(targetcons != NULL);
12266 
12267  sourcedata = SCIPconsGetData(sourcecons);
12268  assert(sourcedata != NULL);
12269  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12270 
12271  /* get event handler */
12272  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12273  assert(conshdlrdata != NULL);
12274  assert(conshdlrdata->eventhdlr != NULL);
12275 
12276  /* create target constraint data */
12277  SCIP_CALL( consdataCreate(scip, &targetdata,
12278  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12279 
12280  /* create target constraint */
12281  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12282  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12283  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12284  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12285  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12286 
12287  /* catch events for variables */
12288  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12289 
12290  return SCIP_OKAY;
12291 }
12292 /**! [SnippetConsTransKnapsack]*/
12293 
12294 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12295 static
12296 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12297 { /*lint --e{715}*/
12298  int i;
12299 
12300  *infeasible = FALSE;
12301 
12302  for( i = 0; i < nconss && !(*infeasible); i++ )
12303  {
12304  assert(SCIPconsIsInitial(conss[i]));
12305  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12306  }
12307 
12308  return SCIP_OKAY;
12309 }
12310 
12311 /** separation method of constraint handler for LP solutions */
12312 static
12313 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12314 { /*lint --e{715}*/
12315  SCIP_CONSHDLRDATA* conshdlrdata;
12316  SCIP_Bool sepacardinality;
12317  SCIP_Bool cutoff;
12318 
12319  SCIP_Real loclowerbound;
12320  SCIP_Real glblowerbound;
12321  SCIP_Real cutoffbound;
12322  SCIP_Real maxbound;
12323 
12324  int depth;
12325  int nrounds;
12326  int sepafreq;
12327  int sepacardfreq;
12328  int ncuts;
12329  int maxsepacuts;
12330  int i;
12331 
12332  *result = SCIP_DIDNOTRUN;
12333 
12334  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12335  assert(conshdlrdata != NULL);
12336 
12337  depth = SCIPgetDepth(scip);
12338  nrounds = SCIPgetNSepaRounds(scip);
12339 
12340  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12341  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12342 
12343  /* only call the separator a given number of times at each node */
12344  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12345  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12346  return SCIP_OKAY;
12347 
12348  /* check, if we should additionally separate knapsack cuts */
12349  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12350  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12351  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12352  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12353 
12354  /* check dual bound to see if we want to produce knapsack cuts at this node */
12355  loclowerbound = SCIPgetLocalLowerbound(scip);
12356  glblowerbound = SCIPgetLowerbound(scip);
12357  cutoffbound = SCIPgetCutoffbound(scip);
12358  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12359  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12360  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12361 
12362  /* get the maximal number of cuts allowed in a separation round */
12363  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12364 
12365  *result = SCIP_DIDNOTFIND;
12366  ncuts = 0;
12367  cutoff = FALSE;
12368 
12369  /* separate useful constraints */
12370  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12371  {
12372  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12373  }
12374 
12375  /* adjust return value */
12376  if ( cutoff )
12377  *result = SCIP_CUTOFF;
12378  else if ( ncuts > 0 )
12379  *result = SCIP_SEPARATED;
12380 
12381  return SCIP_OKAY;
12382 }
12383 
12384 
12385 /** separation method of constraint handler for arbitrary primal solutions */
12386 static
12387 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12388 { /*lint --e{715}*/
12389  SCIP_CONSHDLRDATA* conshdlrdata;
12390  SCIP_Bool sepacardinality;
12391  SCIP_Bool cutoff;
12392 
12393  int depth;
12394  int nrounds;
12395  int sepafreq;
12396  int sepacardfreq;
12397  int ncuts;
12398  int maxsepacuts;
12399  int i;
12400 
12401  *result = SCIP_DIDNOTRUN;
12402 
12403  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12404  assert(conshdlrdata != NULL);
12405 
12406  depth = SCIPgetDepth(scip);
12407  nrounds = SCIPgetNSepaRounds(scip);
12408 
12409  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12410  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12411 
12412  /* only call the separator a given number of times at each node */
12413  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12414  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12415  return SCIP_OKAY;
12416 
12417  /* check, if we should additionally separate knapsack cuts */
12418  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12419  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12420  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12421  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12422 
12423  /* get the maximal number of cuts allowed in a separation round */
12424  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12425 
12426  *result = SCIP_DIDNOTFIND;
12427  ncuts = 0;
12428  cutoff = FALSE;
12429 
12430  /* separate useful constraints */
12431  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12432  {
12433  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12434  }
12435 
12436  /* adjust return value */
12437  if ( cutoff )
12438  *result = SCIP_CUTOFF;
12439  else if( ncuts > 0 )
12440  *result = SCIP_SEPARATED;
12441 
12442  return SCIP_OKAY;
12443 }
12444 
12445 /** constraint enforcing method of constraint handler for LP solutions */
12446 static
12447 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12448 { /*lint --e{715}*/
12449  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12450 
12451  return SCIP_OKAY;
12452 }
12453 
12454 /** constraint enforcing method of constraint handler for relaxation solutions */
12455 static
12456 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12457 { /*lint --e{715}*/
12458  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12459 
12460  return SCIP_OKAY;
12461 }
12462 
12463 /** constraint enforcing method of constraint handler for pseudo solutions */
12464 static
12465 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12466 { /*lint --e{715}*/
12467  SCIP_Bool violated;
12468  int i;
12469 
12470  for( i = 0; i < nconss; i++ )
12471  {
12472  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12473  if( violated )
12474  {
12475  *result = SCIP_INFEASIBLE;
12476  return SCIP_OKAY;
12477  }
12478  }
12479  *result = SCIP_FEASIBLE;
12480 
12481  return SCIP_OKAY;
12482 }
12483 
12484 /** feasibility check method of constraint handler for integral solutions */
12485 static
12486 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12487 { /*lint --e{715}*/
12488  SCIP_Bool violated;
12489  int i;
12490 
12491  *result = SCIP_FEASIBLE;
12492 
12493  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12494  {
12495  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12496  if( violated )
12497  *result = SCIP_INFEASIBLE;
12498  }
12499 
12500  return SCIP_OKAY;
12501 }
12502 
12503 /** domain propagation method of constraint handler */
12504 static
12505 SCIP_DECL_CONSPROP(consPropKnapsack)
12506 { /*lint --e{715}*/
12507  SCIP_CONSHDLRDATA* conshdlrdata;
12508  SCIP_Bool cutoff;
12509  SCIP_Bool redundant;
12510  SCIP_Bool inpresolve;
12511  int nfixedvars;
12512  int i;
12514  cutoff = FALSE;
12515  nfixedvars = 0;
12516 
12517  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12518  assert(conshdlrdata != NULL);
12519 
12520  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12521  assert(!inpresolve || SCIPinProbing(scip));
12522 
12523  /* process useful constraints */
12524  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12525  {
12526  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12527  * otherwise the multi-aggregation should be resolved
12528  */
12529  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12530  continue;
12531 #ifndef NDEBUG
12532  else
12533  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12534 #endif
12535 
12536  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12537 
12538  /* unmark the constraint to be propagated */
12539  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12540  }
12541 
12542  /* adjust result code */
12543  if( cutoff )
12544  *result = SCIP_CUTOFF;
12545  else if( nfixedvars > 0 )
12546  *result = SCIP_REDUCEDDOM;
12547  else
12548  *result = SCIP_DIDNOTFIND;
12549 
12550  return SCIP_OKAY; /*lint !e438*/
12551 }
12552 
12553 /** presolving method of constraint handler */
12554 static
12555 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12556 { /*lint --e{574,715}*/
12557  SCIP_CONSHDLRDATA* conshdlrdata;
12558  SCIP_CONSDATA* consdata;
12559  SCIP_CONS* cons;
12560  SCIP_Bool cutoff;
12561  SCIP_Bool redundant;
12562  SCIP_Bool success;
12563  int oldnfixedvars;
12564  int oldnchgbds;
12565  int oldndelconss;
12566  int oldnaddconss;
12567  int oldnchgcoefs;
12568  int oldnchgsides;
12569  int firstchange;
12570  int c;
12571  SCIP_Bool newchanges;
12572 
12573  /* remember old preprocessing counters */
12574  cutoff = FALSE;
12575  oldnfixedvars = *nfixedvars;
12576  oldnchgbds = *nchgbds;
12577  oldndelconss = *ndelconss;
12578  oldnaddconss = *naddconss;
12579  oldnchgcoefs = *nchgcoefs;
12580  oldnchgsides = *nchgsides;
12581  firstchange = INT_MAX;
12582 
12583  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12584 
12585  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12586  assert(conshdlrdata != NULL);
12587 
12588  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12589  {
12590  int thisnfixedvars;
12591  int thisnchgbds;
12592 
12593  cons = conss[c];
12594  consdata = SCIPconsGetData(cons);
12595  assert(consdata != NULL);
12596 
12597  /* update data structures */
12598  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12599  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12600  {
12601  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12602  if( cutoff )
12603  break;
12604  }
12605 
12606  /* force presolving the constraint in the initial round */
12607  if( nrounds == 0 )
12608  consdata->presolvedtiming = 0;
12609  else if( consdata->presolvedtiming >= presoltiming )
12610  continue;
12611 
12612  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12613  SCIPdebugPrintCons(scip, cons, NULL);
12614  consdata->presolvedtiming = presoltiming;
12615 
12616  thisnfixedvars = *nfixedvars;
12617  thisnchgbds = *nchgbds;
12618 
12619  /* merge constraint, so propagation works better */
12620  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12621  if( cutoff )
12622  break;
12623 
12624  /* add cliques in the knapsack to the clique table */
12625  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12626  {
12627  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12628  if( cutoff )
12629  break;
12630  }
12631 
12632  /* propagate constraint */
12633  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12634  {
12635  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12636 
12637  if( cutoff )
12638  break;
12639  if( redundant )
12640  {
12641  (*ndelconss)++;
12642  continue;
12643  }
12644  }
12645 
12646  /* remove again all fixed variables, if further fixings were found */
12647  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12648  {
12649  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12650  if( cutoff )
12651  break;
12652 
12653  thisnfixedvars = *nfixedvars;
12654  }
12655 
12656  if( !SCIPconsIsModifiable(cons) )
12657  {
12658  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12659  if( consdata->weightsum <= consdata->capacity )
12660  {
12661  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12662  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12663  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12664  continue;
12665  }
12666 
12667  /* divide weights by their greatest common divisor */
12668  normalizeWeights(cons, nchgcoefs, nchgsides);
12669 
12670  /* try to simplify inequalities */
12671  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12672  {
12673  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12674  if( cutoff )
12675  break;
12676 
12677  if( SCIPconsIsDeleted(cons) )
12678  continue;
12679 
12680  /* remove again all fixed variables, if further fixings were found */
12681  if( *nfixedvars > thisnfixedvars )
12682  {
12683  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12684  if( cutoff )
12685  break;
12686  }
12687  }
12688 
12689  /* tighten capacity and weights */
12690  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12691  if( cutoff )
12692  break;
12693 
12694  if( SCIPconsIsActive(cons) )
12695  {
12696  if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12697  {
12698  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12699  * dual reduction
12700  */
12701  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12702  if( redundant )
12703  continue;
12704  }
12705 
12706  /* check if knapsack constraint is parallel to objective function */
12707  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12708  }
12709  }
12710  /* remember the first changed constraint to begin the next aggregation round with */
12711  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12712  firstchange = c;
12713  }
12714 
12715  /* preprocess pairs of knapsack constraints */
12716  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12717  {
12718  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12719  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12720  }
12721 
12722  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12723  success = TRUE;
12724  else
12725  success = FALSE;
12726 
12727  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12728  {
12729  SCIP_Longint npaircomparisons;
12730 
12731  npaircomparisons = 0;
12732  oldndelconss = *ndelconss;
12733  oldnchgsides = *nchgsides;
12734  oldnchgcoefs = *nchgcoefs;
12735 
12736  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12737  {
12738  cons = conss[c];
12739  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12740  continue;
12741 
12742  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12743 
12744  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12745 
12746  if( npaircomparisons > NMINCOMPARISONS )
12747  {
12748  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12749  success = TRUE;
12750  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12751  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12752  break;
12753  oldndelconss = *ndelconss;
12754  oldnchgsides = *nchgsides;
12755  oldnchgcoefs = *nchgcoefs;
12756  npaircomparisons = 0;
12757  }
12758  }
12759  }
12760 #ifdef WITH_CARDINALITY_UPGRADE
12761  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12762  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12763  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12764  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12765  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12766  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12767  * as well, we better keep this code disabled. */
12768  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12769  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12770  {
12771  SCIP_HASHMAP* varhash;
12772  SCIP_VAR** cardvars;
12773  SCIP_Real* cardweights;
12774  int noldupgdconss;
12775  int nscipvars;
12776  int makeupgrade;
12777 
12778  noldupgdconss = *nupgdconss;
12779  nscipvars = SCIPgetNVars(scip);
12780  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12781  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12782 
12783  /* set up hash map */
12784  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12785 
12786  /* We loop through all cardinality constraints twice:
12787  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12788  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12789  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12790  * - Second, upgrade knapsack constraints to cardinality constraints. */
12791  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12792  {
12793  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12794  {
12795  SCIP_CONS* cardcons;
12796  SCIP_VAR** vars;
12797  SCIP_Longint* weights;
12798  int nvars;
12799  int v;
12800 
12801  cons = conss[c];
12802  assert( cons != NULL );
12803  consdata = SCIPconsGetData(cons);
12804  assert( consdata != NULL );
12805 
12806  nvars = consdata->nvars;
12807  vars = consdata->vars;
12808  weights = consdata->weights;
12809 
12810  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12811  * - all variables must be binary (always true)
12812  * - all coefficients must be 1.0
12813  * - the right hand side must be smaller than nvars
12814  */
12815  if ( consdata->capacity >= nvars )
12816  continue;
12817 
12818  /* the weights are sorted: check first and last weight */
12819  assert( consdata->sorted );
12820  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12821  continue;
12822 
12823  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12824  for (v = 0; v < nvars; ++v)
12825  {
12826  SCIP_BOUNDTYPE* impltypes;
12827  SCIP_Real* implbounds;
12828  SCIP_VAR** implvars;
12829  SCIP_VAR* var;
12830  int nimpls;
12831  int j;
12832 
12833  var = consdata->vars[v];
12834  assert( var != NULL );
12835  assert( SCIPvarIsBinary(var) );
12836 
12837  /* ignore non-active variables */
12838  if ( ! SCIPvarIsActive(var) )
12839  break;
12840 
12841  /* be sure that implication variable has zero objective */
12842  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12843  break;
12844 
12845  nimpls = SCIPvarGetNImpls(var, FALSE);
12846  implvars = SCIPvarGetImplVars(var, FALSE);
12847  implbounds = SCIPvarGetImplBounds(var, FALSE);
12848  impltypes = SCIPvarGetImplTypes(var, FALSE);
12849 
12850  for (j = 0; j < nimpls; ++j)
12851  {
12852  /* be sure that continuous variable is fixed to 0 */
12853  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12854  continue;
12855 
12856  /* cannot currently deal with nonzero fixings */
12857  if ( ! SCIPisZero(scip, implbounds[j]) )
12858  continue;
12859 
12860  /* number of down locks should be one */
12861  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12862  continue;
12863 
12864  cardvars[v] = implvars[j];
12865  cardweights[v] = (SCIP_Real) v;
12866 
12867  break;
12868  }
12869 
12870  /* found no variable upper bound candidate -> exit */
12871  if ( j >= nimpls )
12872  break;
12873  }
12874 
12875  /* did not find fitting variable upper bound for some variable -> exit */
12876  if ( v < nvars )
12877  break;
12878 
12879  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12880  * in which the binary variable is involved in */
12881  if ( makeupgrade == 0 )
12882  {
12883  for (v = 0; v < nvars; ++v)
12884  {
12885  if ( SCIPhashmapExists(varhash, vars[v]) )
12886  {
12887  int image;
12888 
12889  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12890  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12891  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12892  }
12893  else
12894  {
12895  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12896  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12897  assert( SCIPhashmapExists(varhash, vars[v]) );
12898  }
12899  }
12900  }
12901  else
12902  {
12903  SCIP_CONS* origcons;
12904 
12905  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12906  * knapsack constraint coincides with the number of variable up locks */
12907  for (v = 0; v < nvars; ++v)
12908  {
12909  assert( SCIPhashmapExists(varhash, vars[v]) );
12910  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12911  break;
12912  }
12913  if ( v < nvars )
12914  break;
12915 
12916  /* store that we have upgraded */
12917  conshdlrdata->upgradedcard = TRUE;
12918 
12919  /* at this point we found suitable variable upper bounds */
12920  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12921 
12922  /* create cardinality constraint */
12923  assert( ! SCIPconsIsModifiable(cons) );
12924  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12928 #ifdef SCIP_DEBUG
12929  SCIPprintCons(scip, cons, NULL);
12930  SCIPinfoMessage(scip, NULL, "\n");
12931  SCIPprintCons(scip, cardcons, NULL);
12932  SCIPinfoMessage(scip, NULL, "\n");
12933 #endif
12934  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12935  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12936  ++(*nupgdconss);
12937 
12938  /* delete oknapsack constraint */
12939  SCIP_CALL( SCIPdelCons(scip, cons) );
12940  ++(*ndelconss);
12941 
12942  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12943  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12944  * although the cardinality constraint is satisfied. */
12945  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12946  assert( origcons != NULL );
12947  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12948 
12949  for (v = 0; v < nvars; ++v)
12950  {
12951  int image;
12952 
12953  assert ( SCIPhashmapExists(varhash, vars[v]) );
12954  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12955  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12956  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12957  }
12958  }
12959  }
12960  }
12961  SCIPhashmapFree(&varhash);
12962  SCIPfreeBufferArray(scip, &cardweights);
12963  SCIPfreeBufferArray(scip, &cardvars);
12964 
12965  if ( *nupgdconss > noldupgdconss )
12966  success = TRUE;
12967  }
12968 #endif
12969 
12970  if( cutoff )
12971  *result = SCIP_CUTOFF;
12972  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12973  *result = SCIP_SUCCESS;
12974  else
12975  *result = SCIP_DIDNOTFIND;
12976 
12977  return SCIP_OKAY;
12978 }
12979 
12980 /** propagation conflict resolving method of constraint handler */
12981 static
12982 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12983 { /*lint --e{715}*/
12984  SCIP_CONSDATA* consdata;
12985  SCIP_Longint capsum;
12986  int i;
12987 
12988  assert(result != NULL);
12989 
12990  consdata = SCIPconsGetData(cons);
12991  assert(consdata != NULL);
12992 
12993  /* check if we fixed a binary variable to one (due to negated clique) */
12994  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12995  {
12996  for( i = 0; i < consdata->nvars; ++i )
12997  {
12998  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12999  {
13000  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13001  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13002  break;
13003  }
13004  }
13005  assert(i < consdata->nvars);
13006  }
13007  else
13008  {
13009  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13010  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13011  * knapsack constraint, see one above call of SCIPinferBinvarCons
13012  */
13013  if( inferinfo < 0 )
13014  capsum = 0;
13015  else
13016  {
13017  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13018  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13019  */
13020  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13021  capsum = consdata->weights[inferinfo];
13022  else
13023  {
13024  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13025  {}
13026  assert(i < consdata->nvars);
13027  capsum = consdata->weights[i];
13028  }
13029  }
13030 
13031  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13032  * the capacity
13033  */
13034  if( capsum <= consdata->capacity )
13035  {
13036  for( i = 0; i < consdata->nvars; i++ )
13037  {
13038  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13039  {
13040  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13041  capsum += consdata->weights[i];
13042  if( capsum > consdata->capacity )
13043  break;
13044  }
13045  }
13046  }
13047  }
13048 
13049  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13050  * to zero can included negated clique information. A negated clique means, that at most one of the clique
13051  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13052  * used to fix variables to zero.
13053  *
13054  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13055  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13056  * one.
13057  */
13058  *result = SCIP_SUCCESS;
13059 
13060  return SCIP_OKAY;
13061 }
13062 
13063 /** variable rounding lock method of constraint handler */
13064 /**! [SnippetConsLockKnapsack] */
13065 static
13066 SCIP_DECL_CONSLOCK(consLockKnapsack)
13067 { /*lint --e{715}*/
13068  SCIP_CONSDATA* consdata;
13069  int i;
13070 
13071  consdata = SCIPconsGetData(cons);
13072  assert(consdata != NULL);
13073 
13074  for( i = 0; i < consdata->nvars; i++)
13075  {
13076  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13077  }
13078 
13079  return SCIP_OKAY;
13080 }
13081 /**! [SnippetConsLockKnapsack] */
13082 
13083 /** constraint activation notification method of constraint handler */
13084 static
13085 SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13086 { /*lint --e{715}*/
13087  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisNLPConstructed(scip) )
13088  {
13089  SCIP_CALL( addNlrow(scip, cons) );
13090  }
13091 
13092  return SCIP_OKAY;
13094 
13095 /** constraint deactivation notification method of constraint handler */
13096 static
13097 SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13098 { /*lint --e{715}*/
13099  SCIP_CONSDATA* consdata;
13100 
13101  assert(cons != NULL);
13102 
13103  consdata = SCIPconsGetData(cons);
13104  assert(consdata != NULL);
13106  /* remove row from NLP, if still in solving
13107  * if we are in exitsolve, the whole NLP will be freed anyway
13108  */
13109  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13110  {
13111  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13112  }
13113 
13114  return SCIP_OKAY;
13115 }
13116 
13117 /** variable deletion method of constraint handler */
13118 static
13119 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13120 {
13121  assert(scip != NULL);
13122  assert(conshdlr != NULL);
13123  assert(conss != NULL || nconss == 0);
13124 
13125  if( nconss > 0 )
13126  {
13127  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13128  }
13129 
13130  return SCIP_OKAY;
13131 }
13132 
13133 /** constraint display method of constraint handler */
13134 static
13135 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13136 { /*lint --e{715}*/
13137  SCIP_CONSDATA* consdata;
13138  int i;
13139 
13140  assert( scip != NULL );
13141  assert( conshdlr != NULL );
13142  assert( cons != NULL );
13144  consdata = SCIPconsGetData(cons);
13145  assert(consdata != NULL);
13146 
13147  for( i = 0; i < consdata->nvars; ++i )
13148  {
13149  if( i > 0 )
13150  SCIPinfoMessage(scip, file, " ");
13151  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13152  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13153  }
13154  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13155 
13156  return SCIP_OKAY;
13157 }
13158 
13159 /** constraint copying method of constraint handler */
13160 static
13161 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13162 { /*lint --e{715}*/
13163  SCIP_VAR** sourcevars;
13164  SCIP_Longint* weights;
13165  SCIP_Real* coefs;
13166  const char* consname;
13167  int nvars;
13168  int v;
13170  /* get variables and coefficients of the source constraint */
13171  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13172  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13173  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13174 
13175  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13176  for( v = 0; v < nvars; ++v )
13177  coefs[v] = (SCIP_Real) weights[v];
13178 
13179  if( name != NULL )
13180  consname = name;
13181  else
13182  consname = SCIPconsGetName(sourcecons);
13183 
13184  /* copy the logic using the linear constraint copy method */
13185  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13186  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13187  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13188  assert(cons != NULL);
13189 
13190  SCIPfreeBufferArray(scip, &coefs);
13191 
13192  return SCIP_OKAY;
13193 }
13194 
13195 /** constraint parsing method of constraint handler */
13196 static
13197 SCIP_DECL_CONSPARSE(consParseKnapsack)
13198 { /*lint --e{715}*/
13199  SCIP_VAR* var;
13200  SCIP_Longint weight;
13201  SCIP_VAR** vars;
13202  SCIP_Longint* weights;
13203  SCIP_Longint capacity;
13204  char* endptr;
13205  int nread;
13206  int nvars;
13207  int varssize;
13208 
13209  assert(scip != NULL);
13210  assert(success != NULL);
13211  assert(str != NULL);
13212  assert(name != NULL);
13213  assert(cons != NULL);
13214 
13215  *success = TRUE;
13216 
13217  nvars = 0;
13218  varssize = 5;
13219  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13220  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13221 
13222  while( *str != '\0' )
13223  {
13224  /* try to parse coefficient, and use 1 if not successful */
13225  weight = 1;
13226  nread = 0;
13227  sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13228  str += nread;
13229 
13230  /* parse variable name */
13231  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13232 
13233  if( var == NULL )
13234  {
13235  endptr = strchr(endptr, '<');
13236 
13237  if( endptr == NULL )
13238  {
13239  SCIPerrorMessage("no capacity found\n");
13240  *success = FALSE;
13241  }
13242  else
13243  str = endptr;
13244 
13245  break;
13246  }
13247 
13248  str = endptr;
13249 
13250  /* store weight and variable */
13251  if( varssize <= nvars )
13252  {
13253  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13254  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13255  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13256  }
13257 
13258  vars[nvars] = var;
13259  weights[nvars] = weight;
13260  ++nvars;
13261 
13262  /* skip whitespace */
13263  SCIP_CALL( SCIPskipSpace((char**)&str) );
13264  }
13265 
13266  if( *success )
13267  {
13268  if( strncmp(str, "<=", 2) != 0 )
13269  {
13270  SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13271  *success = FALSE;
13272  }
13273  else
13274  {
13275  str += 2;
13276  }
13277  }
13278 
13279  if( *success )
13280  {
13281  /* skip whitespace */
13282  SCIP_CALL( SCIPskipSpace((char**)&str) );
13283 
13284  /* coverity[secure_coding] */
13285  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13286  {
13287  SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13288  *success = FALSE;
13289  }
13290  else
13291  {
13292  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13293  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13294  }
13295  }
13296 
13297  SCIPfreeBufferArray(scip, &vars);
13298  SCIPfreeBufferArray(scip, &weights);
13299 
13300  return SCIP_OKAY;
13301 }
13302 
13303 /** constraint method of constraint handler which returns the variables (if possible) */
13304 static
13305 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13306 { /*lint --e{715}*/
13307  SCIP_CONSDATA* consdata;
13308 
13309  consdata = SCIPconsGetData(cons);
13310  assert(consdata != NULL);
13311 
13312  if( varssize < consdata->nvars )
13313  (*success) = FALSE;
13314  else
13315  {
13316  assert(vars != NULL);
13317 
13318  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13319  (*success) = TRUE;
13320  }
13321 
13322  return SCIP_OKAY;
13323 }
13324 
13325 /** constraint method of constraint handler which returns the number of variables (if possible) */
13326 static
13327 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13328 { /*lint --e{715}*/
13329  SCIP_CONSDATA* consdata;
13330 
13331  consdata = SCIPconsGetData(cons);
13332  assert(consdata != NULL);
13333 
13334  (*nvars) = consdata->nvars;
13335  (*success) = TRUE;
13336 
13337  return SCIP_OKAY;
13338 }
13339 
13340 /*
13341  * Event handler
13342  */
13343 
13344 /** execution method of bound change event handler */
13345 static
13346 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13347 { /*lint --e{715}*/
13348  SCIP_CONSDATA* consdata;
13349 
13350  assert(eventdata != NULL);
13351  assert(eventdata->cons != NULL);
13352 
13353  consdata = SCIPconsGetData(eventdata->cons);
13354  assert(consdata != NULL);
13355 
13356  switch( SCIPeventGetType(event) )
13357  {
13359  consdata->onesweightsum += eventdata->weight;
13360  consdata->presolvedtiming = 0;
13361  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13362  break;
13364  consdata->onesweightsum -= eventdata->weight;
13365  break;
13367  consdata->presolvedtiming = 0;
13368  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13369  break;
13370  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13371  if( !consdata->existmultaggr )
13372  {
13373  SCIP_VAR* var;
13374  var = SCIPeventGetVar(event);
13375  assert(var != NULL);
13376 
13377  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13379  {
13380  consdata->existmultaggr = TRUE;
13381  consdata->merged = FALSE;
13382  }
13383  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13385  consdata->merged = FALSE;
13386  }
13387  /*lint -fallthrough*/
13388  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13389  consdata->presolvedtiming = 0;
13390  break;
13392  consdata->varsdeleted = TRUE;
13393  break;
13394  default:
13395  SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13396  return SCIP_INVALIDDATA;
13397  }
13398 
13399  return SCIP_OKAY;
13400 }
13401 
13402 
13403 /*
13404  * constraint specific interface methods
13405  */
13406 
13407 /** creates the handler for knapsack constraints and includes it in SCIP */
13409  SCIP* scip /**< SCIP data structure */
13410  )
13411 {
13412  SCIP_EVENTHDLRDATA* eventhdlrdata;
13413  SCIP_CONSHDLRDATA* conshdlrdata;
13414  SCIP_CONSHDLR* conshdlr;
13415 
13416  /* create knapsack constraint handler data */
13417  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13418 
13419  /* include event handler for bound change events */
13420  eventhdlrdata = NULL;
13421  conshdlrdata->eventhdlr = NULL;
13422  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13423  eventExecKnapsack, eventhdlrdata) );
13424 
13425  /* get event handler for bound change events */
13426  if( conshdlrdata->eventhdlr == NULL )
13427  {
13428  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13429  return SCIP_PLUGINNOTFOUND;
13430  }
13431 
13432  /* include constraint handler */
13435  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13436  conshdlrdata) );
13437 
13438  assert(conshdlr != NULL);
13439 
13440  /* set non-fundamental callbacks via specific setter functions */
13441  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13442  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13443  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13444  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13445  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13446  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13447  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13448  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13449  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13450  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13451  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13452  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13453  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13454  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13455  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13456  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13457  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13458  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13459  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13461  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13462  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13464  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13465  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13466 
13467  if( SCIPfindConshdlr(scip,"linear") != NULL )
13468  {
13469  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13471  }
13472 
13473  /* add knapsack constraint handler parameters */
13474  SCIP_CALL( SCIPaddIntParam(scip,
13475  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13476  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13477  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13479  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13480  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13481  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13483  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13484  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13485  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13486  SCIP_CALL( SCIPaddIntParam(scip,
13487  "constraints/" CONSHDLR_NAME "/maxrounds",
13488  "maximal number of separation rounds per node (-1: unlimited)",
13489  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13490  SCIP_CALL( SCIPaddIntParam(scip,
13491  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13492  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13493  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13494  SCIP_CALL( SCIPaddIntParam(scip,
13495  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13496  "maximal number of cuts separated per separation round",
13497  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13498  SCIP_CALL( SCIPaddIntParam(scip,
13499  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13500  "maximal number of cuts separated per separation round in the root node",
13501  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13503  "constraints/" CONSHDLR_NAME "/disaggregation",
13504  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13505  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13507  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13508  "should presolving try to simplify knapsacks",
13509  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13511  "constraints/" CONSHDLR_NAME "/negatedclique",
13512  "should negated clique information be used in solving process",
13513  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13515  "constraints/" CONSHDLR_NAME "/presolpairwise",
13516  "should pairwise constraint comparison be performed in presolving?",
13517  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13519  "constraints/" CONSHDLR_NAME "/presolusehashing",
13520  "should hash table be used for detecting redundant constraints in advance",
13521  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13523  "constraints/" CONSHDLR_NAME "/dualpresolving",
13524  "should dual presolving steps be performed?",
13525  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13527  "constraints/" CONSHDLR_NAME "/usegubs",
13528  "should GUB information be used for separation?",
13529  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13531  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13532  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13533  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13535  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13536  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13537  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13539  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13540  "should clique partition information be updated when old partition seems outdated?",
13541  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13543  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13544  "factor on the growth of global cliques to decide when to update a previous "
13545  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13546  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13547 #ifdef WITH_CARDINALITY_UPGRADE
13549  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13550  "if TRUE then try to update knapsack constraints to cardinality constraints",
13551  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13552 #endif
13553  return SCIP_OKAY;
13554 }
13555 
13556 /** creates and captures a knapsack constraint
13557  *
13558  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13559  */
13560 /**! [SnippetConsCreationKnapsack] */
13562  SCIP* scip, /**< SCIP data structure */
13563  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13564  const char* name, /**< name of constraint */
13565  int nvars, /**< number of items in the knapsack */
13566  SCIP_VAR** vars, /**< array with item variables */
13567  SCIP_Longint* weights, /**< array with item weights */
13568  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13569  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13570  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13571  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13572  * Usually set to TRUE. */
13573  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13574  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13575  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13576  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13577  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13578  * Usually set to TRUE. */
13579  SCIP_Bool local, /**< is constraint only valid locally?
13580  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13581  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13582  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13583  * adds coefficients to this constraint. */
13584  SCIP_Bool dynamic, /**< is constraint subject to aging?
13585  * Usually set to FALSE. Set to TRUE for own cuts which
13586  * are separated as constraints. */
13587  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13588  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13589  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13590  * if it may be moved to a more global node?
13591  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13592  )
13593 {
13594  SCIP_CONSHDLRDATA* conshdlrdata;
13595  SCIP_CONSHDLR* conshdlr;
13596  SCIP_CONSDATA* consdata;
13597 
13598  /* find the knapsack constraint handler */
13599  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13600  if( conshdlr == NULL )
13601  {
13602  SCIPerrorMessage("knapsack constraint handler not found\n");
13603  return SCIP_PLUGINNOTFOUND;
13604  }
13605 
13606  /* get event handler */
13607  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13608  assert(conshdlrdata != NULL);
13609  assert(conshdlrdata->eventhdlr != NULL);
13610 
13611  /* create constraint data */
13612  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13613 
13614  /* create constraint */
13615  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13616  local, modifiable, dynamic, removable, stickingatnode) );
13617 
13618  /* catch events for variables */
13619  if( SCIPisTransformed(scip) )
13620  {
13621  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13622  }
13623 
13624  return SCIP_OKAY;
13625 }
13626 /**! [SnippetConsCreationKnapsack] */
13627 
13628 /** creates and captures a knapsack constraint
13629  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13630  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13631  *
13632  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13633  *
13634  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13635  */
13637  SCIP* scip, /**< SCIP data structure */
13638  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13639  const char* name, /**< name of constraint */
13640  int nvars, /**< number of items in the knapsack */
13641  SCIP_VAR** vars, /**< array with item variables */
13642  SCIP_Longint* weights, /**< array with item weights */
13643  SCIP_Longint capacity /**< capacity of knapsack */
13644  )
13645 {
13646  assert(scip != NULL);
13647 
13648  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13649  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13650 
13651  return SCIP_OKAY;
13652 }
13653 
13654 /** adds new item to knapsack constraint */
13656  SCIP* scip, /**< SCIP data structure */
13657  SCIP_CONS* cons, /**< constraint data */
13658  SCIP_VAR* var, /**< item variable */
13659  SCIP_Longint weight /**< item weight */
13660  )
13661 {
13662  assert(var != NULL);
13663  assert(scip != NULL);
13664 
13665  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13666  {
13667  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13668  return SCIP_INVALIDDATA;
13669  }
13670 
13671  SCIP_CALL( addCoef(scip, cons, var, weight) );
13672 
13673  return SCIP_OKAY;
13674 }
13675 
13676 /** gets the capacity of the knapsack constraint */
13678  SCIP* scip, /**< SCIP data structure */
13679  SCIP_CONS* cons /**< constraint data */
13680  )
13681 {
13682  SCIP_CONSDATA* consdata;
13683 
13684  assert(scip != NULL);
13686  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13687  {
13688  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13689  SCIPABORT();
13690  return 0; /*lint !e527*/
13691  }
13692 
13693  consdata = SCIPconsGetData(cons);
13694  assert(consdata != NULL);
13695 
13696  return consdata->capacity;
13697 }
13698 
13699 /** changes capacity of the knapsack constraint
13700  *
13701  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13702  */
13704  SCIP* scip, /**< SCIP data structure */
13705  SCIP_CONS* cons, /**< constraint data */
13706  SCIP_Longint capacity /**< new capacity of knapsack */
13707  )
13708 {
13709  SCIP_CONSDATA* consdata;
13710 
13711  assert(scip != NULL);
13712 
13713  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13714  {
13715  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13716  return SCIP_INVALIDDATA;
13717  }
13718 
13719  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13720  {
13721  SCIPerrorMessage("method can only be called during problem creation stage\n");
13722  return SCIP_INVALIDDATA;
13723  }
13724 
13725  consdata = SCIPconsGetData(cons);
13726  assert(consdata != NULL);
13727 
13728  consdata->capacity = capacity;
13729 
13730  return SCIP_OKAY;
13731 }
13732 
13733 /** gets the number of items in the knapsack constraint */
13735  SCIP* scip, /**< SCIP data structure */
13736  SCIP_CONS* cons /**< constraint data */
13737  )
13738 {
13739  SCIP_CONSDATA* consdata;
13740 
13741  assert(scip != NULL);
13743  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13744  {
13745  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13746  SCIPABORT();
13747  return -1; /*lint !e527*/
13748  }
13749 
13750  consdata = SCIPconsGetData(cons);
13751  assert(consdata != NULL);
13752 
13753  return consdata->nvars;
13754 }
13755 
13756 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13758  SCIP* scip, /**< SCIP data structure */
13759  SCIP_CONS* cons /**< constraint data */
13760  )
13761 {
13762  SCIP_CONSDATA* consdata;
13763 
13764  assert(scip != NULL);
13766  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13767  {
13768  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13769  SCIPABORT();
13770  return NULL; /*lint !e527*/
13771  }
13772 
13773  consdata = SCIPconsGetData(cons);
13774  assert(consdata != NULL);
13775 
13776  return consdata->vars;
13777 }
13778 
13779 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13781  SCIP* scip, /**< SCIP data structure */
13782  SCIP_CONS* cons /**< constraint data */
13783  )
13784 {
13785  SCIP_CONSDATA* consdata;
13786 
13787  assert(scip != NULL);
13789  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13790  {
13791  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13792  SCIPABORT();
13793  return NULL; /*lint !e527*/
13794  }
13795 
13796  consdata = SCIPconsGetData(cons);
13797  assert(consdata != NULL);
13798 
13799  return consdata->weights;
13800 }
13801 
13802 /** gets the dual solution of the knapsack constraint in the current LP */
13804  SCIP* scip, /**< SCIP data structure */
13805  SCIP_CONS* cons /**< constraint data */
13806  )
13807 {
13808  SCIP_CONSDATA* consdata;
13809 
13810  assert(scip != NULL);
13812  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13813  {
13814  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13815  SCIPABORT();
13816  return SCIP_INVALID; /*lint !e527*/
13817  }
13818 
13819  consdata = SCIPconsGetData(cons);
13820  assert(consdata != NULL);
13821 
13822  if( consdata->row != NULL )
13823  return SCIProwGetDualsol(consdata->row);
13824  else
13825  return 0.0;
13826 }
13827 
13828 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13830  SCIP* scip, /**< SCIP data structure */
13831  SCIP_CONS* cons /**< constraint data */
13832  )
13833 {
13834  SCIP_CONSDATA* consdata;
13835 
13836  assert(scip != NULL);
13838  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13839  {
13840  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13841  SCIPABORT();
13842  return SCIP_INVALID; /*lint !e527*/
13843  }
13844 
13845  consdata = SCIPconsGetData(cons);
13846  assert(consdata != NULL);
13847 
13848  if( consdata->row != NULL )
13849  return SCIProwGetDualfarkas(consdata->row);
13850  else
13851  return 0.0;
13852 }
13853 
13854 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13855  * the user must not modify the row!
13856  */
13858  SCIP* scip, /**< SCIP data structure */
13859  SCIP_CONS* cons /**< constraint data */
13860  )
13861 {
13862  SCIP_CONSDATA* consdata;
13863 
13864  assert(scip != NULL);
13866  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13867  {
13868  SCIPerrorMessage("constraint is not a knapsack\n");
13869  SCIPABORT();
13870  return NULL; /*lint !e527*/
13871  }
13872 
13873  consdata = SCIPconsGetData(cons);
13874  assert(consdata != NULL);
13875 
13876  return consdata->row;
13877 }
13878 
13879 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
13881  SCIP* scip, /**< SCIP data structure */
13882  SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13883  SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13884  )
13885 {
13886  SCIP_CONSHDLR* conshdlr;
13887  SCIP_CONS** conss;
13888  int nconss;
13889  int i;
13890 
13891  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13892  if( conshdlr == NULL )
13893  return SCIP_OKAY;
13894 
13895  assert(infeasible != NULL);
13896  *infeasible = FALSE;
13897 
13898  nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13899  conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13900 
13901  for( i = 0; i < nconss; ++i )
13902  {
13903  SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13904 
13905  if( *infeasible )
13906  break;
13907  }
13908 
13909  return SCIP_OKAY;
13910 }
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:4212
#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:1693
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:18115
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:11465
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3380
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
SCIP_RETCODE SCIPskipSpace(char **s)
Definition: misc.c:10777
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:5203
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:2128
#define CONSHDLR_DESC
Definition: cons_knapsack.c:77
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:3296
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:92
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:8349
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17693
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:1597
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:3307
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:1992
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2497
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:18093
#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:17901
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:12300
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:3354
public methods for conflict handler plugins and conflict analysis
#define CONSHDLR_ENFOPRIORITY
Definition: cons_knapsack.c:79
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:2843
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17681
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
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:1560
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17957
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:18264
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:1248
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17422
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:81
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:4554
#define FALSE
Definition: def.h:96
#define MAX_CLIQUELENGTH
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3024
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11096
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:86
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10788
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:3585
#define CONSHDLR_EAGERFREQ
Definition: cons_knapsack.c:83
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8369
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18135
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:3142
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17591
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:900
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4861
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:8399
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:5320
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:94
#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:18105
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:5091
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:8359
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:17312
#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:1480
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:91
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:8151
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18253
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:2172
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:2246
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:17717
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17523
#define DEFAULT_SEPACARDFREQ
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3373
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4259
#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:6921
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:17911
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:12208
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:78
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:4182
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
#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:3474
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:2898
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:4437
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:8090
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18167
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8309
#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:17242
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:3058
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4202
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:394
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:18125
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17705
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:2627
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)
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18157
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8329
#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:9279
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:18211
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:87
#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:18179
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:7256
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8110
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11932
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3392
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:8219
#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:8289
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8259
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17749
#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:95
#define CONSHDLR_NAME
Definition: cons_knapsack.c:76
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:8276
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:136
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:88
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition: lp.c:17325
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4351
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:2220
#define IDX(j, d)
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2558
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17669
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:18225
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:330
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4631
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:2296
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
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:3696
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:18196
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:8120
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:4574
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:7575
#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:1947
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17361
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7475
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1214
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:8339
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:12268
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:4617
public methods for message handling
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8279
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:96
#define SCIP_INVALID
Definition: def.h:206
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8269
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18147
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:82
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:89
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:9468
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17581
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:17967
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3370
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17384
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:3231
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:366
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:17433
#define MAXCOVERSIZEITERLEWI
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9032
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:17463
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:8629
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:5723
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:80
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:71
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1527
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:17571
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17397
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