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-2024 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 #include "scip/symmetry_graph.h"
73 #include <ctype.h>
74 #include <string.h>
75 
76 #ifdef WITH_CARDINALITY_UPGRADE
77 #include "scip/cons_cardinality.h"
78 #endif
79 
80 /* constraint handler properties */
81 #define CONSHDLR_NAME "knapsack"
82 #define CONSHDLR_DESC "knapsack constraint of the form a^T x <= b, x binary and a >= 0"
83 #define CONSHDLR_SEPAPRIORITY +600000 /**< priority of the constraint handler for separation */
84 #define CONSHDLR_ENFOPRIORITY -600000 /**< priority of the constraint handler for constraint enforcing */
85 #define CONSHDLR_CHECKPRIORITY -600000 /**< priority of the constraint handler for checking feasibility */
86 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
87 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
88 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
89  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
90 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
91 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
92 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
93 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
94 
95 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
96 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
97 
98 #define EVENTHDLR_NAME "knapsack"
99 #define EVENTHDLR_DESC "bound change event handler for knapsack constraints"
100 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
101  | SCIP_EVENTTYPE_UBTIGHTENED \
102  | SCIP_EVENTTYPE_VARFIXED \
103  | SCIP_EVENTTYPE_VARDELETED \
104  | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
105 
106 #define LINCONSUPGD_PRIORITY +100000 /**< priority of the constraint handler for upgrading of linear constraints */
108 #define MAX_USECLIQUES_SIZE 1000 /**< maximal number of items in knapsack where clique information is used */
109 #define MAX_ZEROITEMS_SIZE 10000 /**< maximal number of items to store in the zero list in preprocessing */
111 #define KNAPSACKRELAX_MAXDELTA 0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
112 #define KNAPSACKRELAX_MAXDNOM 1000LL /**< maximal allowed denominator in knapsack rational relaxation */
113 #define KNAPSACKRELAX_MAXSCALE 1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
115 #define DEFAULT_SEPACARDFREQ 1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
116 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
117 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
118 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
119 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in the root node */
120 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
121  * to best node's dual bound for separating knapsack cuts */
122 #define DEFAULT_DISAGGREGATION TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
123 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
124 #define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in solving process */
126 #define MAXABSVBCOEF 1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
127 #define USESUPADDLIFT FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
129 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
130 #define HASHSIZE_KNAPSACKCONS 500 /**< minimal size of hash table in linear constraint tables */
132 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
133 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
134 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
135  * comparison round */
136 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
137 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
138  * function defining an upper bound and prevent these constraints from
139  * entering the LP */
140 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
141  * function defining a lower bound and prevent these constraints from
142  * entering the LP */
143 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
144 #define MAXCOVERSIZEITERLEWI 1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
146 #define DEFAULT_USEGUBS FALSE /**< should GUB information be used for separation? */
147 #define GUBCONSGROWVALUE 6 /**< memory growing value for GUB constraint array */
148 #define GUBSPLITGNC1GUBS FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
149 #define DEFAULT_CLQPARTUPDATEFAC 1.5 /**< factor on the growth of global cliques to decide when to update a previous
150  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
151 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
152 #define MAXNCLIQUEVARSCOMP 1000000 /**< limit on number of pairwise comparisons in clique partitioning algorithm */
153 #ifdef WITH_CARDINALITY_UPGRADE
154 #define DEFAULT_UPGDCARDINALITY FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
155 #endif
157 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
158 
159 /*
160  * Data structures
161  */
162 
163 /** constraint handler data */
164 struct SCIP_ConshdlrData
165 {
166  int* ints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
167  * you have to clear it at the end, exists only in presolving stage */
168  int* ints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
169  * you have to clear it at the end, exists only in presolving stage */
170  SCIP_Longint* longints1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
171  * you have to clear it at the end, exists only in presolving stage */
172  SCIP_Longint* longints2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
173  * you have to clear it at the end, exists only in presolving stage */
174  SCIP_Bool* bools1; /**< cleared memory array, all entries are set to zero in initpre, if you use this
175  * you have to clear it at the end, exists only in presolving stage */
176  SCIP_Bool* bools2; /**< cleared memory array, all entries are set to zero in initpre, if you use this
177  * you have to clear it at the end, exists only in presolving stage */
178  SCIP_Bool* bools3; /**< cleared memory array, all entries are set to zero in initpre, if you use this
179  * you have to clear it at the end, exists only in presolving stage */
180  SCIP_Bool* bools4; /**< cleared memory array, all entries are set to zero in initpre, if you use this
181  * you have to clear it at the end, exists only in presolving stage */
182  SCIP_Real* reals1; /**< cleared memory array, all entries are set to zero in consinit, if you use this
183  * you have to clear it at the end */
184  int ints1size; /**< size of ints1 array */
185  int ints2size; /**< size of ints2 array */
186  int longints1size; /**< size of longints1 array */
187  int longints2size; /**< size of longints2 array */
188  int bools1size; /**< size of bools1 array */
189  int bools2size; /**< size of bools2 array */
190  int bools3size; /**< size of bools3 array */
191  int bools4size; /**< size of bools4 array */
192  int reals1size; /**< size of reals1 array */
193  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
194  SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
195  * to best node's dual bound for separating knapsack cuts */
196  int sepacardfreq; /**< multiplier on separation frequency, how often knapsack cuts are separated */
197  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
198  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
199  int maxsepacuts; /**< maximal number of cuts separated per separation round */
200  int maxsepacutsroot; /**< maximal number of cuts separated per separation round in the root node */
201  SCIP_Bool disaggregation; /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
202  SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
203  SCIP_Bool negatedclique; /**< should negated clique information be used in solving process */
204  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
205  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
206  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
207  SCIP_Bool usegubs; /**< should GUB information be used for separation? */
208  SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
209  * function defining an upper bound and prevent these constraints from
210  * entering the LP */
211  SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
212  * function defining a lower bound and prevent these constraints from
213  * entering the LP */
214  SCIP_Bool updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
215  SCIP_Real cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
216  SCIP_Real clqpartupdatefac; /**< factor on the growth of global cliques to decide when to update a previous
217  * (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
218 #ifdef WITH_CARDINALITY_UPGRADE
219  SCIP_Bool upgdcardinality; /**< if TRUE then try to update knapsack constraints to cardinality constraints */
220  SCIP_Bool upgradedcard; /**< whether we have already upgraded knapsack constraints to cardinality constraints */
221 #endif
222 };
223 
224 
225 /** constraint data for knapsack constraints */
226 struct SCIP_ConsData
227 {
228  SCIP_VAR** vars; /**< variables in knapsack constraint */
229  SCIP_Longint* weights; /**< weights of variables in knapsack constraint */
230  SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
231  int* cliquepartition; /**< clique indices of the clique partition */
232  int* negcliquepartition; /**< clique indices of the negated clique partition */
233  SCIP_ROW* row; /**< corresponding LP row */
234  SCIP_NLROW* nlrow; /**< corresponding NLP row */
235  int nvars; /**< number of variables in knapsack constraint */
236  int varssize; /**< size of vars, weights, and eventdata arrays */
237  int ncliques; /**< number of cliques in the clique partition */
238  int nnegcliques; /**< number of cliques in the negated clique partition */
239  int ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
240  int ncliqueslastpart; /**< number of global cliques the last time a clique partition was computed */
241  SCIP_Longint capacity; /**< capacity of knapsack */
242  SCIP_Longint weightsum; /**< sum of all weights */
243  SCIP_Longint onesweightsum; /**< sum of weights of variables fixed to one */
244  unsigned int presolvedtiming:5; /**< max level in which the knapsack constraint is already presolved */
245  unsigned int sorted:1; /**< are the knapsack items sorted by weight? */
246  unsigned int cliquepartitioned:1;/**< is the clique partition valid? */
247  unsigned int negcliquepartitioned:1;/**< is the negated clique partition valid? */
248  unsigned int merged:1; /**< are the constraint's equal variables already merged? */
249  unsigned int cliquesadded:1; /**< were the cliques of the knapsack already added to clique table? */
250  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
251  unsigned int existmultaggr:1; /**< does this constraint contain multi-aggregations */
252 };
253 
254 /** event data for bound changes events */
255 struct SCIP_EventData
256 {
257  SCIP_CONS* cons; /**< knapsack constraint to process the bound change for */
258  SCIP_Longint weight; /**< weight of variable */
259  int filterpos; /**< position of event in variable's event filter */
260 };
261 
262 
263 /** data structure to combine two sorting key values */
264 struct sortkeypair
265 {
266  SCIP_Real key1; /**< first sort key value */
267  SCIP_Real key2; /**< second sort key value */
268 };
269 typedef struct sortkeypair SORTKEYPAIR;
270 
271 /** status of GUB constraint */
272 enum GUBVarstatus
273 {
274  GUBVARSTATUS_UNINITIAL = -1, /** unintitialized variable status */
275  GUBVARSTATUS_CAPACITYEXCEEDED = 0, /** variable with weight exceeding the knapsack capacity */
276  GUBVARSTATUS_BELONGSTOSET_R = 1, /** variable in noncovervars R */
277  GUBVARSTATUS_BELONGSTOSET_F = 2, /** variable in noncovervars F */
278  GUBVARSTATUS_BELONGSTOSET_C2 = 3, /** variable in covervars C2 */
279  GUBVARSTATUS_BELONGSTOSET_C1 = 4 /** variable in covervars C1 */
280 };
281 typedef enum GUBVarstatus GUBVARSTATUS;
283 /** status of variable in GUB constraint */
285 {
286  GUBCONSSTATUS_UNINITIAL = -1, /** unintitialized GUB constraint status */
287  GUBCONSSTATUS_BELONGSTOSET_GR = 0, /** all GUB variables are in noncovervars R */
288  GUBCONSSTATUS_BELONGSTOSET_GF = 1, /** all GUB variables are in noncovervars F (and noncovervars R) */
289  GUBCONSSTATUS_BELONGSTOSET_GC2 = 2, /** all GUB variables are in covervars C2 */
290  GUBCONSSTATUS_BELONGSTOSET_GNC1 = 3, /** some GUB variables are in covervars C1, others in noncovervars R or F */
291  GUBCONSSTATUS_BELONGSTOSET_GOC1 = 4 /** all GUB variables are in covervars C1 */
292 };
293 typedef enum GUBConsstatus GUBCONSSTATUS;
295 /** data structure of GUB constraints */
297 {
298  int* gubvars; /**< indices of GUB variables in knapsack constraint */
299  GUBVARSTATUS* gubvarsstatus; /**< status of GUB variables */
300  int ngubvars; /**< number of GUB variables */
301  int gubvarssize; /**< size of gubvars array */
302 };
303 typedef struct SCIP_GUBCons SCIP_GUBCONS;
305 /** data structure of a set of GUB constraints */
307 {
308  SCIP_GUBCONS** gubconss; /**< GUB constraints in GUB set */
309  GUBCONSSTATUS* gubconsstatus; /**< status of GUB constraints */
310  int ngubconss; /**< number of GUB constraints */
311  int nvars; /**< number of variables in knapsack constraint */
312  int* gubconssidx; /**< index of GUB constraint (in gubconss array) of each knapsack variable */
313  int* gubvarsidx; /**< index in GUB constraint (in gubvars array) of each knapsack variable */
314 };
315 typedef struct SCIP_GUBSet SCIP_GUBSET;
317 /*
318  * Local methods
319  */
321 /** comparison method for two sorting key pairs */
322 static
323 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
324 {
325  SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
326  SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
327 
328  if( sortkeypair1->key1 < sortkeypair2->key1 )
329  return -1;
330  else if( sortkeypair1->key1 > sortkeypair2->key1 )
331  return +1;
332  else if( sortkeypair1->key2 < sortkeypair2->key2 )
333  return -1;
334  else if( sortkeypair1->key2 > sortkeypair2->key2 )
335  return +1;
336  else
337  return 0;
338 }
339 
340 /** creates event data */
341 static
343  SCIP* scip, /**< SCIP data structure */
344  SCIP_EVENTDATA** eventdata, /**< pointer to store event data */
345  SCIP_CONS* cons, /**< constraint */
346  SCIP_Longint weight /**< weight of variable */
347  )
348 {
349  assert(eventdata != NULL);
351  SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
352  (*eventdata)->cons = cons;
353  (*eventdata)->weight = weight;
354 
355  return SCIP_OKAY;
356 }
357 
358 /** frees event data */
359 static
361  SCIP* scip, /**< SCIP data structure */
362  SCIP_EVENTDATA** eventdata /**< pointer to event data */
363  )
364 {
365  assert(eventdata != NULL);
366 
367  SCIPfreeBlockMemory(scip, eventdata);
369  return SCIP_OKAY;
370 }
371 
372 /** sorts items in knapsack with nonincreasing weights */
373 static
374 void sortItems(
375  SCIP_CONSDATA* consdata /**< constraint data */
376  )
377 {
378  assert(consdata != NULL);
379  assert(consdata->nvars == 0 || consdata->vars != NULL);
380  assert(consdata->nvars == 0 || consdata->weights != NULL);
381  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
382  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
383 
384  if( !consdata->sorted )
385  {
386  int pos;
387  int lastcliquenum;
388  int v;
389 
390  /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
391  * sorted by first array in non-increasing order via sort template */
393  consdata->weights,
394  (void**)consdata->vars,
395  (void**)consdata->eventdata,
396  consdata->cliquepartition,
397  consdata->negcliquepartition,
398  consdata->nvars);
399 
400  v = consdata->nvars - 1;
401  /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
402  while( v >= 0 )
403  {
404  int w = v - 1;
405 
406  while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
407  --w;
408 
409  if( v - w > 1 )
410  {
411  /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
413  (void**)(&(consdata->vars[w+1])),
414  (void**)(&(consdata->eventdata[w+1])),
415  &(consdata->cliquepartition[w+1]),
416  &(consdata->negcliquepartition[w+1]),
417  SCIPvarComp,
418  v - w);
419  }
420  v = w;
421  }
422 
423  /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
424  if( consdata->cliquepartitioned )
425  {
426  lastcliquenum = 0;
427 
428  for( pos = 0; pos < consdata->nvars; ++pos )
429  {
430  /* if the clique number in the normal clique at position pos is greater than the last found clique number the
431  * partition is invalid */
432  if( consdata->cliquepartition[pos] > lastcliquenum )
433  {
434  consdata->cliquepartitioned = FALSE;
435  break;
436  }
437  else if( consdata->cliquepartition[pos] == lastcliquenum )
438  ++lastcliquenum;
439  }
440  }
441  /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
442  if( consdata->negcliquepartitioned )
443  {
444  lastcliquenum = 0;
445 
446  for( pos = 0; pos < consdata->nvars; ++pos )
447  {
448  /* if the clique number in the negated clique at position pos is greater than the last found clique number the
449  * partition is invalid */
450  if( consdata->negcliquepartition[pos] > lastcliquenum )
451  {
452  consdata->negcliquepartitioned = FALSE;
453  break;
454  }
455  else if( consdata->negcliquepartition[pos] == lastcliquenum )
456  ++lastcliquenum;
457  }
458  }
459 
460  consdata->sorted = TRUE;
461  }
462 #ifndef NDEBUG
463  {
464  /* check if the weight array is sorted in a non-increasing way */
465  int i;
466  for( i = 0; i < consdata->nvars-1; ++i )
467  assert(consdata->weights[i] >= consdata->weights[i+1]);
468  }
469 #endif
470 }
471 
472 /** calculates a partition of the variables into cliques */
473 static
475  SCIP* scip, /**< SCIP data structure */
476  SCIP_CONSHDLRDATA* conshdlrdata, /**< knapsack constraint handler data */
477  SCIP_CONSDATA* consdata, /**< constraint data */
478  SCIP_Bool normalclique, /**< Should normal cliquepartition be created? */
479  SCIP_Bool negatedclique /**< Should negated cliquepartition be created? */
480  )
481 {
482  SCIP_Bool ispartitionoutdated;
483  SCIP_Bool isnegpartitionoutdated;
484  assert(consdata != NULL);
485  assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
486 
487  /* rerun eventually if number of global cliques increased considerably since last partition */
488  ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
489  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
490 
491  if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
492  {
493  SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
494  consdata->cliquepartitioned = TRUE;
495  consdata->ncliqueslastpart = SCIPgetNCliques(scip);
496  }
497 
498  /* rerun eventually if number of global cliques increased considerably since last negated partition */
499  isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
500  && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
501 
502  if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
503  {
504  SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
505  consdata->negcliquepartitioned = TRUE;
506  consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
507  }
508  assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
509  assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
510 
511  return SCIP_OKAY;
512 }
513 
514 /** installs rounding locks for the given variable in the given knapsack constraint */
515 static
517  SCIP* scip, /**< SCIP data structure */
518  SCIP_CONS* cons, /**< knapsack constraint */
519  SCIP_VAR* var /**< variable of constraint entry */
520  )
521 {
522  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
523 
524  return SCIP_OKAY;
525 }
526 
527 /** removes rounding locks for the given variable in the given knapsack constraint */
528 static
530  SCIP* scip, /**< SCIP data structure */
531  SCIP_CONS* cons, /**< knapsack constraint */
532  SCIP_VAR* var /**< variable of constraint entry */
533  )
534 {
535  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
536 
537  return SCIP_OKAY;
538 }
539 
540 /** catches bound change events for variables in knapsack */
541 static
543  SCIP* scip, /**< SCIP data structure */
544  SCIP_CONS* cons, /**< constraint */
545  SCIP_CONSDATA* consdata, /**< constraint data */
546  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
547  )
548 {
549  int i;
551  assert(cons != NULL);
552  assert(consdata != NULL);
553  assert(consdata->nvars == 0 || consdata->vars != NULL);
554  assert(consdata->nvars == 0 || consdata->weights != NULL);
555  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
556 
557  for( i = 0; i < consdata->nvars; i++)
558  {
559  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
560  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
561  eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
562  }
563 
564  return SCIP_OKAY;
565 }
566 
567 /** drops bound change events for variables in knapsack */
568 static
570  SCIP* scip, /**< SCIP data structure */
571  SCIP_CONSDATA* consdata, /**< constraint data */
572  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
573  )
574 {
575  int i;
576 
577  assert(consdata != NULL);
578  assert(consdata->nvars == 0 || consdata->vars != NULL);
579  assert(consdata->nvars == 0 || consdata->weights != NULL);
580  assert(consdata->nvars == 0 || consdata->eventdata != NULL);
581 
582  for( i = 0; i < consdata->nvars; i++)
583  {
584  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
585  eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
586  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
587  }
588 
589  return SCIP_OKAY;
590 }
591 
592 /** ensures, that vars and vals arrays can store at least num entries */
593 static
595  SCIP* scip, /**< SCIP data structure */
596  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
597  int num, /**< minimum number of entries to store */
598  SCIP_Bool transformed /**< is constraint from transformed problem? */
599  )
600 {
601  assert(consdata != NULL);
602  assert(consdata->nvars <= consdata->varssize);
603 
604  if( num > consdata->varssize )
605  {
606  int newsize;
607 
608  newsize = SCIPcalcMemGrowSize(scip, num);
609  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
610  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
611  if( transformed )
612  {
613  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
614  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
615  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
616  }
617  else
618  {
619  assert(consdata->eventdata == NULL);
620  assert(consdata->cliquepartition == NULL);
621  assert(consdata->negcliquepartition == NULL);
622  }
623  consdata->varssize = newsize;
624  }
625  assert(num <= consdata->varssize);
626 
627  return SCIP_OKAY;
628 }
629 
630 /** updates all weight sums for fixed and unfixed variables */
631 static
632 void updateWeightSums(
633  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
634  SCIP_VAR* var, /**< variable for this weight */
635  SCIP_Longint weightdelta /**< difference between the old and the new weight of the variable */
636  )
637 {
638  assert(consdata != NULL);
639  assert(var != NULL);
641  consdata->weightsum += weightdelta;
642 
643  if( SCIPvarGetLbLocal(var) > 0.5 )
644  consdata->onesweightsum += weightdelta;
645 
646  assert(consdata->weightsum >= 0);
647  assert(consdata->onesweightsum >= 0);
648 }
649 
650 /** creates knapsack constraint data */
651 static
653  SCIP* scip, /**< SCIP data structure */
654  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
655  int nvars, /**< number of variables in knapsack */
656  SCIP_VAR** vars, /**< variables of knapsack */
657  SCIP_Longint* weights, /**< weights of knapsack items */
658  SCIP_Longint capacity /**< capacity of knapsack */
659  )
660 {
661  int v;
662  SCIP_Longint constant;
663 
664  assert(consdata != NULL);
665 
666  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
667 
668  constant = 0L;
669  (*consdata)->vars = NULL;
670  (*consdata)->weights = NULL;
671  (*consdata)->nvars = 0;
672  if( nvars > 0 )
673  {
674  SCIP_VAR** varsbuffer;
675  SCIP_Longint* weightsbuffer;
676  int k;
677 
678  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
679  SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
680 
681  k = 0;
682  for( v = 0; v < nvars; ++v )
683  {
684  assert(vars[v] != NULL);
685  assert(SCIPvarIsBinary(vars[v]));
686 
687  /* all weight have to be non negative */
688  assert( weights[v] >= 0 );
689 
690  if( weights[v] > 0 )
691  {
692  /* treat fixed variables as constants if problem compression is enabled */
693  if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
694  {
695  /* only if the variable is fixed to 1, we add its weight to the constant */
696  if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
697  constant += weights[v];
698  }
699  else
700  {
701  varsbuffer[k] = vars[v];
702  weightsbuffer[k] = weights[v];
703  ++k;
704  }
705  }
706  }
707  assert(k >= 0);
708  assert(constant >= 0);
709 
710  (*consdata)->nvars = k;
711 
712  /* copy the active variables and weights into the constraint data structure */
713  if( k > 0 )
714  {
715  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
716  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
717  }
718 
719  /* free buffer storage */
720  SCIPfreeBufferArray(scip, &weightsbuffer);
721  SCIPfreeBufferArray(scip, &varsbuffer);
722  }
723 
724  (*consdata)->varssize = (*consdata)->nvars;
725  (*consdata)->capacity = capacity - constant;
726  (*consdata)->eventdata = NULL;
727  (*consdata)->cliquepartition = NULL;
728  (*consdata)->negcliquepartition = NULL;
729  (*consdata)->row = NULL;
730  (*consdata)->nlrow = NULL;
731  (*consdata)->weightsum = 0;
732  (*consdata)->onesweightsum = 0;
733  (*consdata)->ncliques = 0;
734  (*consdata)->nnegcliques = 0;
735  (*consdata)->presolvedtiming = 0;
736  (*consdata)->sorted = FALSE;
737  (*consdata)->cliquepartitioned = FALSE;
738  (*consdata)->negcliquepartitioned = FALSE;
739  (*consdata)->ncliqueslastpart = -1;
740  (*consdata)->ncliqueslastnegpart = -1;
741  (*consdata)->merged = FALSE;
742  (*consdata)->cliquesadded = FALSE;
743  (*consdata)->varsdeleted = FALSE;
744  (*consdata)->existmultaggr = FALSE;
745 
746  /* get transformed variables, if we are in the transformed problem */
747  if( SCIPisTransformed(scip) )
748  {
749  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
750 
751  for( v = 0; v < (*consdata)->nvars; v++ )
752  {
753  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
754  assert(var != NULL);
755  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
756  }
757 
758  /* allocate memory for additional data structures */
759  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
760  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
761  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
762  }
763 
764  /* calculate sum of weights and capture variables */
765  for( v = 0; v < (*consdata)->nvars; ++v )
766  {
767  /* calculate sum of weights */
768  updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
769 
770  /* capture variables */
771  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
772  }
773  return SCIP_OKAY;
774 }
775 
776 /** frees knapsack constraint data */
777 static
779  SCIP* scip, /**< SCIP data structure */
780  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
781  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
782  )
783 {
784  assert(consdata != NULL);
785  assert(*consdata != NULL);
787  if( (*consdata)->row != NULL )
788  {
789  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
790  }
791  if( (*consdata)->nlrow != NULL )
792  {
793  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
794  }
795  if( (*consdata)->eventdata != NULL )
796  {
797  SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
798  SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
799  }
800  if( (*consdata)->negcliquepartition != NULL )
801  {
802  SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
803  }
804  if( (*consdata)->cliquepartition != NULL )
805  {
806  SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
807  }
808  if( (*consdata)->vars != NULL )
809  {
810  int v;
811 
812  /* release variables */
813  for( v = 0; v < (*consdata)->nvars; v++ )
814  {
815  assert((*consdata)->vars[v] != NULL);
816  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
817  }
818 
819  assert( (*consdata)->weights != NULL );
820  assert( (*consdata)->varssize > 0 );
821  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
822  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
823  }
824 
825  SCIPfreeBlockMemory(scip, consdata);
826 
827  return SCIP_OKAY;
828 }
829 
830 /** changes a single weight in knapsack constraint data */
831 static
832 void consdataChgWeight(
833  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
834  int item, /**< item number */
835  SCIP_Longint newweight /**< new weight of item */
836  )
837 {
838  SCIP_Longint oldweight;
839  SCIP_Longint weightdiff;
841  assert(consdata != NULL);
842  assert(0 <= item && item < consdata->nvars);
843 
844  oldweight = consdata->weights[item];
845  weightdiff = newweight - oldweight;
846  consdata->weights[item] = newweight;
847 
848  /* update weight sums for all and fixed variables */
849  updateWeightSums(consdata, consdata->vars[item], weightdiff);
850 
851  if( consdata->eventdata != NULL )
852  {
853  assert(consdata->eventdata[item] != NULL);
854  assert(consdata->eventdata[item]->weight == oldweight);
855  consdata->eventdata[item]->weight = newweight;
856  }
857 
858  consdata->presolvedtiming = 0;
859  consdata->sorted = FALSE;
860 
861  /* recalculate cliques extraction after a weight was increased */
862  if( oldweight < newweight )
863  {
864  consdata->cliquesadded = FALSE;
865  }
866 }
867 
868 /** creates LP row corresponding to knapsack constraint */
869 static
871  SCIP* scip, /**< SCIP data structure */
872  SCIP_CONS* cons /**< knapsack constraint */
873  )
874 {
875  SCIP_CONSDATA* consdata;
876  int i;
877 
878  consdata = SCIPconsGetData(cons);
879  assert(consdata != NULL);
880  assert(consdata->row == NULL);
881 
882  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
883  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
885 
886  SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
887  for( i = 0; i < consdata->nvars; ++i )
888  {
889  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
890  }
891  SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
892 
893  return SCIP_OKAY;
894 }
895 
896 /** adds linear relaxation of knapsack constraint to the LP */
897 static
899  SCIP* scip, /**< SCIP data structure */
900  SCIP_CONS* cons, /**< knapsack constraint */
901  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
902  )
903 {
904  SCIP_CONSDATA* consdata;
905 
906  assert( cutoff != NULL );
907  *cutoff = FALSE;
908 
909  consdata = SCIPconsGetData(cons);
910  assert(consdata != NULL);
911 
912  if( consdata->row == NULL )
913  {
914  SCIP_CALL( createRelaxation(scip, cons) );
915  }
916  assert(consdata->row != NULL);
917 
918  /* insert LP row as cut */
919  if( !SCIProwIsInLP(consdata->row) )
920  {
921  SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
922  SCIPconsGetName(cons), consdata->capacity);
923  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
924  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
925  }
926 
927  return SCIP_OKAY;
928 }
929 
930 /** adds knapsack constraint as row to the NLP, if not added yet */
931 static
933  SCIP* scip, /**< SCIP data structure */
934  SCIP_CONS* cons /**< knapsack constraint */
935  )
936 {
937  SCIP_CONSDATA* consdata;
938 
939  assert(SCIPisNLPConstructed(scip));
941  /* skip deactivated, redundant, or local linear constraints (the NLP does not allow for local rows at the moment) */
942  if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
943  return SCIP_OKAY;
944 
945  consdata = SCIPconsGetData(cons);
946  assert(consdata != NULL);
947 
948  if( consdata->nlrow == NULL )
949  {
950  SCIP_Real* coefs;
951  int i;
952 
953  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
954  for( i = 0; i < consdata->nvars; ++i )
955  coefs[i] = (SCIP_Real)consdata->weights[i]; /*lint !e613*/
956 
957  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
958  consdata->nvars, consdata->vars, coefs, NULL,
959  -SCIPinfinity(scip), (SCIP_Real)consdata->capacity, SCIP_EXPRCURV_LINEAR) );
960 
961  assert(consdata->nlrow != NULL);
962 
963  SCIPfreeBufferArray(scip, &coefs);
964  }
965 
966  if( !SCIPnlrowIsInNLP(consdata->nlrow) )
967  {
968  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
969  }
970 
971  return SCIP_OKAY;
972 }
973 
974 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
975 static
977  SCIP* scip, /**< SCIP data structure */
978  SCIP_CONS* cons, /**< constraint to check */
979  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
980  SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
981  SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
982  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
983  )
984 {
985  SCIP_CONSDATA* consdata;
986 
987  assert(violated != NULL);
988 
989  consdata = SCIPconsGetData(cons);
990  assert(consdata != NULL);
991 
992  SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
993  SCIPconsGetName(cons), (void*)sol, checklprows);
994 
995  *violated = FALSE;
996 
997  if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
998  {
999  SCIP_Real normsum = 0.0;
1000  SCIP_Real hugesum = 0.0;
1001  SCIP_Real absviol;
1002  SCIP_Real relviol;
1003  int v;
1004 
1005  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1006  * enforcement
1007  */
1008  if( sol == NULL )
1009  {
1010  SCIP_CALL( SCIPincConsAge(scip, cons) );
1011  }
1012 
1013  /* sum separately over normal and huge weight contributions in order to reduce numerical cancellation */
1014  for( v = consdata->nvars - 1; v >= 0; --v )
1015  {
1016  assert(SCIPvarIsBinary(consdata->vars[v]));
1017 
1018  if( SCIPisHugeValue(scip, (SCIP_Real)consdata->weights[v]) )
1019  hugesum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1020  else
1021  normsum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1022  }
1023 
1024  /* calculate constraint violation and update it in solution */
1025  normsum += hugesum;
1026 
1027  if( normsum > consdata->capacity )
1028  {
1029  absviol = normsum - consdata->capacity;
1030  relviol = SCIPrelDiff(normsum, (SCIP_Real)consdata->capacity);
1031  }
1032  else
1033  {
1034  absviol = 0.0;
1035  relviol = 0.0;
1036  }
1037 
1038  if( sol != NULL )
1039  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1040 
1041  if( SCIPisFeasPositive(scip, absviol) )
1042  {
1043  *violated = TRUE;
1044 
1045  /* only reset constraint age if we are in enforcement */
1046  if( sol == NULL )
1047  {
1048  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1049  }
1050 
1051  if( printreason )
1052  {
1053  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1054 
1055  SCIPinfoMessage(scip, NULL, ";\n");
1056  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1057  }
1058  }
1059  }
1060 
1061  return SCIP_OKAY;
1062 }
1063 
1064 /* IDX computes the integer index for the optimal solution array */
1065 #define IDX(j,d) ((j)*(intcap)+(d))
1066 
1067 /** solves knapsack problem in maximization form exactly using dynamic programming;
1068  * if needed, one can provide arrays to store all selected items and all not selected items
1069  *
1070  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1071  *
1072  * @note the algorithm will first compute a greedy solution and terminate
1073  * if the greedy solution is proven to be optimal.
1074  * The dynamic programming algorithm runs with a time and space complexity
1075  * of O(nitems * capacity).
1076  *
1077  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1078  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1079  * to be checked whether they are faster and whether they can reconstruct the solution.
1080  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1081  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1082  * This could be implemented, however, it would be technically a bit cumbersome,
1083  * since one needs the greedy solution and the LP-value for this.
1084  * This is currently only available after the redundant items have already been sorted out.
1085  */
1087  SCIP* scip, /**< SCIP data structure */
1088  int nitems, /**< number of available items */
1089  SCIP_Longint* weights, /**< item weights */
1090  SCIP_Real* profits, /**< item profits */
1091  SCIP_Longint capacity, /**< capacity of knapsack */
1092  int* items, /**< item numbers */
1093  int* solitems, /**< array to store items in solution, or NULL */
1094  int* nonsolitems, /**< array to store items not in solution, or NULL */
1095  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1096  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1097  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1098  SCIP_Bool* success /**< pointer to store if an error occured during solving
1099  * (normally a memory problem) */
1100  )
1101 {
1102  SCIP_RETCODE retcode;
1103  SCIP_Real* tempsort;
1104  SCIP_Real* optvalues;
1105  int intcap;
1106  int d;
1107  int j;
1108  int greedymedianpos;
1109  SCIP_Longint weightsum;
1110  int* myitems;
1111  SCIP_Longint* myweights;
1112  SCIP_Real* realweights;
1113  int* allcurrminweight;
1114  SCIP_Real* myprofits;
1115  int nmyitems;
1116  SCIP_Longint gcd;
1117  SCIP_Longint minweight;
1118  SCIP_Longint maxweight;
1119  int currminweight;
1120  SCIP_Longint greedysolweight;
1121  SCIP_Real greedysolvalue;
1122  SCIP_Real greedyupperbound;
1123  SCIP_Bool eqweights;
1124  SCIP_Bool intprofits;
1125 
1126  assert(weights != NULL);
1127  assert(profits != NULL);
1128  assert(capacity >= 0);
1129  assert(items != NULL);
1130  assert(nitems >= 0);
1131  assert(success != NULL);
1132 
1133  *success = TRUE;
1134 
1135 #ifndef NDEBUG
1136  for( j = nitems - 1; j >= 0; --j )
1137  assert(weights[j] >= 0);
1138 #endif
1139 
1140  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1141 
1142  /* initializing solution value */
1143  if( solval != NULL )
1144  *solval = 0.0;
1145 
1146  /* init solution information */
1147  if( solitems != NULL )
1148  {
1149  assert(items != NULL);
1150  assert(nsolitems != NULL);
1151  assert(nonsolitems != NULL);
1152  assert(nnonsolitems != NULL);
1153 
1154  *nnonsolitems = 0;
1155  *nsolitems = 0;
1156  }
1157 
1158  /* allocate temporary memory */
1159  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1160  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1161  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1162  nmyitems = 0;
1163  weightsum = 0;
1164  minweight = SCIP_LONGINT_MAX;
1165  maxweight = 0;
1166 
1167  /* remove unnecessary items */
1168  for( j = 0; j < nitems; ++j )
1169  {
1170  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1171 
1172  /* item does not fit */
1173  if( weights[j] > capacity )
1174  {
1175  if( solitems != NULL )
1176  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1177  }
1178  /* item is not profitable */
1179  else if( profits[j] <= 0.0 )
1180  {
1181  if( solitems != NULL )
1182  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1183  }
1184  /* item always fits */
1185  else if( weights[j] == 0 )
1186  {
1187  if( solitems != NULL )
1188  solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1189 
1190  if( solval != NULL )
1191  *solval += profits[j];
1192  }
1193  /* all important items */
1194  else
1195  {
1196  myweights[nmyitems] = weights[j];
1197  myprofits[nmyitems] = profits[j];
1198  myitems[nmyitems] = items[j];
1199 
1200  /* remember smallest item */
1201  if( myweights[nmyitems] < minweight )
1202  minweight = myweights[nmyitems];
1203 
1204  /* remember bigest item */
1205  if( myweights[nmyitems] > maxweight )
1206  maxweight = myweights[nmyitems];
1207 
1208  weightsum += myweights[nmyitems];
1209  ++nmyitems;
1210  }
1211  }
1212 
1213  intprofits = TRUE;
1214  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1215  for( j = 0; j < nmyitems && intprofits; ++j )
1216  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1217 
1218  /* if no item is left then goto end */
1219  if( nmyitems == 0 )
1220  {
1221  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1222 
1223  goto TERMINATE;
1224  }
1225 
1226  /* if all items fit, we also do not need to do the expensive stuff later on */
1227  if( weightsum > 0 && weightsum <= capacity )
1228  {
1229  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1230 
1231  for( j = nmyitems - 1; j >= 0; --j )
1232  {
1233  if( solitems != NULL )
1234  solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1235 
1236  if( solval != NULL )
1237  *solval += myprofits[j];
1238  }
1239 
1240  goto TERMINATE;
1241  }
1242 
1243  assert(0 < minweight && minweight <= capacity );
1244  assert(0 < maxweight && maxweight <= capacity);
1245 
1246  /* make weights relatively prime */
1247  eqweights = TRUE;
1248  if( maxweight > 1 )
1249  {
1250  /* determine greatest common divisor */
1251  gcd = myweights[nmyitems - 1];
1252  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1253  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1254 
1255  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1256 
1257  /* divide by greatest common divisor */
1258  if( gcd > 1 )
1259  {
1260  for( j = nmyitems - 1; j >= 0; --j )
1261  {
1262  myweights[j] /= gcd;
1263  eqweights = eqweights && (myweights[j] == 1);
1264  }
1265  capacity /= gcd;
1266  minweight /= gcd;
1267  }
1268  else
1269  eqweights = FALSE;
1270  }
1271  assert(minweight <= capacity);
1272 
1273  /* if only one item fits, then take the best */
1274  if( minweight > capacity / 2 )
1275  {
1276  int p;
1277 
1278  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1279 
1280  p = nmyitems - 1;
1281 
1282  /* find best item */
1283  for( j = nmyitems - 2; j >= 0; --j )
1284  {
1285  if( myprofits[j] > myprofits[p] )
1286  p = j;
1287  }
1288 
1289  /* update solution information */
1290  if( solitems != NULL )
1291  {
1292  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1293 
1294  solitems[(*nsolitems)++] = myitems[p];
1295  for( j = nmyitems - 1; j >= 0; --j )
1296  {
1297  if( j != p )
1298  nonsolitems[(*nnonsolitems)++] = myitems[j];
1299  }
1300  }
1301  /* update solution value */
1302  if( solval != NULL )
1303  *solval += myprofits[p];
1304 
1305  goto TERMINATE;
1306  }
1307 
1308  /* if all items have the same weight, then take the best */
1309  if( eqweights )
1310  {
1311  SCIP_Real addval = 0.0;
1312 
1313  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1314 
1315  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1316 
1317  /* update solution information */
1318  if( solitems != NULL || solval != NULL )
1319  {
1320  SCIP_Longint i;
1321 
1322  /* if all items would fit we had handled this case before */
1323  assert((SCIP_Longint) nmyitems > capacity);
1324  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1325 
1326  /* take the first best items into the solution */
1327  for( i = capacity - 1; i >= 0; --i )
1328  {
1329  if( solitems != NULL )
1330  solitems[(*nsolitems)++] = myitems[i];
1331  addval += myprofits[i];
1332  }
1333 
1334  if( solitems != NULL )
1335  {
1336  /* the rest are not in the solution */
1337  for( i = nmyitems - 1; i >= capacity; --i )
1338  nonsolitems[(*nnonsolitems)++] = myitems[i];
1339  }
1340  }
1341  /* update solution value */
1342  if( solval != NULL )
1343  {
1344  assert(addval > 0.0);
1345  *solval += addval;
1346  }
1347 
1348  goto TERMINATE;
1349  }
1350 
1351  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1352 
1353  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1354  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1355  */
1356  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1357  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1358 
1359  for( j = 0; j < nmyitems; ++j )
1360  {
1361  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1362  realweights[j] = (SCIP_Real)myweights[j];
1363  }
1364 
1365  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1366  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1367 
1368  SCIPfreeBufferArray(scip, &realweights);
1369  SCIPfreeBufferArray(scip, &tempsort);
1370 
1371  /* initialize values for greedy solution information */
1372  greedysolweight = 0;
1373  greedysolvalue = 0.0;
1374 
1375  /* determine greedy solution */
1376  for( j = 0; j < greedymedianpos; ++j )
1377  {
1378  assert(myweights[j] <= capacity);
1379 
1380  /* update greedy solution weight and value */
1381  greedysolweight += myweights[j];
1382  greedysolvalue += myprofits[j];
1383  }
1384 
1385  assert(0 < greedysolweight && greedysolweight <= capacity);
1386  assert(greedysolvalue > 0.0);
1387 
1388  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1389  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1390  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1391  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1392  if( intprofits )
1393  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1394  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1395  {
1396  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1397 
1398  /* update solution information */
1399  if( solitems != NULL )
1400  {
1401  int l;
1402 
1403  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1404 
1405  /* collect items */
1406  for( l = 0; l < j; ++l )
1407  solitems[(*nsolitems)++] = myitems[l];
1408  for ( ; l < nmyitems; ++l )
1409  nonsolitems[(*nnonsolitems)++] = myitems[l];
1410  }
1411  /* update solution value */
1412  if( solval != NULL )
1413  {
1414  assert(greedysolvalue > 0.0);
1415  *solval += greedysolvalue;
1416  }
1417 
1418  goto TERMINATE;
1419  }
1420 
1421  /* in the following table we do not need the first minweight columns */
1422  capacity -= (minweight - 1);
1423 
1424  /* we can only handle integers */
1425  if( capacity >= INT_MAX )
1426  {
1427  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1428 
1429  *success = FALSE;
1430  goto TERMINATE;
1431  }
1432  assert(capacity < INT_MAX);
1433 
1434  intcap = (int)capacity;
1435  assert(intcap >= 0);
1436  assert(nmyitems > 0);
1437  assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1438 
1439  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1440  * computing the size for the allocation
1441  */
1442  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*/
1443  {
1444  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1445 
1446  *success = FALSE;
1447  goto TERMINATE;
1448  }
1449 
1450  /* allocate temporary memory and check for memory exceedance */
1451  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1452  if( retcode == SCIP_NOMEMORY )
1453  {
1454  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1455 
1456  *success = FALSE;
1457  goto TERMINATE;
1458  }
1459  else
1460  {
1461  SCIP_CALL( retcode );
1462  }
1463 
1464  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1465 
1466  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1467  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1468  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1469  * 'nmyitem' values
1470  */
1471  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1472  assert(myweights[0] - minweight < INT_MAX);
1473  currminweight = (int) (myweights[0] - minweight);
1474  allcurrminweight[0] = currminweight;
1475 
1476  /* fills first row of dynamic programming table with optimal values */
1477  for( d = currminweight; d < intcap; ++d )
1478  optvalues[d] = myprofits[0];
1479 
1480  /* fills dynamic programming table with optimal values */
1481  for( j = 1; j < nmyitems; ++j )
1482  {
1483  int intweight;
1484 
1485  /* compute important part of weight, which will be represented in the table */
1486  intweight = (int)(myweights[j] - minweight);
1487  assert(0 <= intweight && intweight < intcap);
1488 
1489  /* copy all nonzeros from row above */
1490  for( d = currminweight; d < intweight && d < intcap; ++d )
1491  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1492 
1493  /* update corresponding row */
1494  for( d = intweight; d < intcap; ++d )
1495  {
1496  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1497  if( d < currminweight )
1498  optvalues[IDX(j,d)] = myprofits[j];
1499  else
1500  {
1501  SCIP_Real sumprofit;
1502 
1503  if( d - myweights[j] < currminweight )
1504  sumprofit = myprofits[j];
1505  else
1506  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1507 
1508  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1509  }
1510  }
1511 
1512  /* update currminweight */
1513  if( intweight < currminweight )
1514  currminweight = intweight;
1515 
1516  allcurrminweight[j] = currminweight;
1517  }
1518 
1519  /* update optimal solution by following the table */
1520  if( solitems != NULL )
1521  {
1522  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1523  d = intcap - 1;
1524 
1525  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1526 
1527  /* insert all items in (non-) solution vector */
1528  for( j = nmyitems - 1; j > 0; --j )
1529  {
1530  /* if the following condition holds this means all remaining items does not fit anymore */
1531  if( d < allcurrminweight[j] )
1532  {
1533  /* we cannot have exceeded our capacity */
1534  assert((SCIP_Longint) d >= -minweight);
1535  break;
1536  }
1537 
1538  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1539  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1540  {
1541  solitems[(*nsolitems)++] = myitems[j];
1542 
1543  /* check that we do not have an underflow */
1544  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1545  d = (int)(d - myweights[j]);
1546  }
1547  /* collect non-solution items */
1548  else
1549  nonsolitems[(*nnonsolitems)++] = myitems[j];
1550  }
1551 
1552  /* insert remaining items */
1553  if( d >= allcurrminweight[j] )
1554  {
1555  assert(j == 0);
1556  solitems[(*nsolitems)++] = myitems[j];
1557  }
1558  else
1559  {
1560  assert(j >= 0);
1561  assert(d < allcurrminweight[j]);
1562 
1563  for( ; j >= 0; --j )
1564  nonsolitems[(*nnonsolitems)++] = myitems[j];
1565  }
1566 
1567  assert(*nsolitems + *nnonsolitems == nitems);
1568  }
1569 
1570  /* update solution value */
1571  if( solval != NULL )
1572  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1573  SCIPfreeBufferArray(scip, &allcurrminweight);
1574 
1575  /* free all temporary memory */
1576  SCIPfreeBufferArray(scip, &optvalues);
1577 
1578  TERMINATE:
1579  SCIPfreeBufferArray(scip, &myitems);
1580  SCIPfreeBufferArray(scip, &myprofits);
1581  SCIPfreeBufferArray(scip, &myweights);
1582 
1583  return SCIP_OKAY;
1584 }
1585 
1586 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1587  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1588  * selected items
1589  */
1591  SCIP* scip, /**< SCIP data structure */
1592  int nitems, /**< number of available items */
1593  SCIP_Longint* weights, /**< item weights */
1594  SCIP_Real* profits, /**< item profits */
1595  SCIP_Longint capacity, /**< capacity of knapsack */
1596  int* items, /**< item numbers */
1597  int* solitems, /**< array to store items in solution, or NULL */
1598  int* nonsolitems, /**< array to store items not in solution, or NULL */
1599  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1600  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1601  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1602  )
1603 {
1604  SCIP_Real* tempsort;
1605  SCIP_Longint solitemsweight;
1606  SCIP_Real* realweights;
1607  int j;
1608  int criticalindex;
1609 
1610  assert(weights != NULL);
1611  assert(profits != NULL);
1612  assert(capacity >= 0);
1613  assert(items != NULL);
1614  assert(nitems >= 0);
1615 
1616  if( solitems != NULL )
1617  {
1618  *nsolitems = 0;
1619  *nnonsolitems = 0;
1620  }
1621  if( solval != NULL )
1622  *solval = 0.0;
1623 
1624  /* initialize data for median search */
1625  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1626  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1627  for( j = nitems - 1; j >= 0; --j )
1628  {
1629  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1630  realweights[j] = (SCIP_Real)weights[j];
1631  }
1632 
1633  /* partially sort indices such that all elements that are larger than the break item appear first */
1634  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1635 
1636  /* selects items as long as they fit into the knapsack */
1637  solitemsweight = 0;
1638  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1639  {
1640  if( solitems != NULL )
1641  solitems[(*nsolitems)++] = items[j];
1642 
1643  if( solval != NULL )
1644  (*solval) += profits[j];
1645  solitemsweight += weights[j];
1646  }
1647  if ( solitems != NULL )
1648  {
1649  for( ; j < nitems; j++ )
1650  nonsolitems[(*nnonsolitems)++] = items[j];
1651  }
1652 
1653  SCIPfreeBufferArray(scip, &realweights);
1654  SCIPfreeBufferArray(scip, &tempsort);
1655 
1656  return SCIP_OKAY;
1657 }
1658 
1659 #ifdef SCIP_DEBUG
1660 /** prints all nontrivial GUB constraints and their LP solution values */
1661 static
1662 void GUBsetPrint(
1663  SCIP* scip, /**< SCIP data structure */
1664  SCIP_GUBSET* gubset, /**< GUB set data structure */
1665  SCIP_VAR** vars, /**< variables in knapsack constraint */
1666  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1667  )
1668 {
1669  int nnontrivialgubconss;
1670  int c;
1671 
1672  nnontrivialgubconss = 0;
1673 
1674  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1675 
1676  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1677  for( c = 0; c < gubset->ngubconss; c++ )
1678  {
1679  SCIP_Real gubsolval;
1680 
1681  assert(gubset->gubconss[c]->ngubvars >= 0);
1682 
1683  /* nontrivial GUB */
1684  if( gubset->gubconss[c]->ngubvars > 1 )
1685  {
1686  int v;
1687 
1688  gubsolval = 0.0;
1689  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1690 
1691  /* print GUB var */
1692  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1693  {
1694  int currentvar;
1695 
1696  currentvar = gubset->gubconss[c]->gubvars[v];
1697  if( solvals != NULL )
1698  {
1699  gubsolval += solvals[currentvar];
1700  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1701  }
1702  else
1703  {
1704  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1705  }
1706  }
1707 
1708  /* check whether LP solution satisfies the GUB constraint */
1709  if( solvals != NULL )
1710  {
1711  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1712  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1713  }
1714  else
1715  {
1716  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1717  }
1718  nnontrivialgubconss++;
1719  }
1720  }
1721 
1722  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1723 }
1724 #endif
1725 
1726 /** creates an empty GUB constraint */
1727 static
1729  SCIP* scip, /**< SCIP data structure */
1730  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1731  )
1732 {
1733  assert(scip != NULL);
1734  assert(gubcons != NULL);
1735 
1736  /* allocate memory for GUB constraint data structures */
1737  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1738  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1739  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1740  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1741 
1742  (*gubcons)->ngubvars = 0;
1743 
1744  return SCIP_OKAY;
1745 }
1746 
1747 /** frees GUB constraint */
1748 static
1749 void GUBconsFree(
1750  SCIP* scip, /**< SCIP data structure */
1751  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1752  )
1753 {
1754  assert(scip != NULL);
1755  assert(gubcons != NULL);
1756  assert((*gubcons)->gubvars != NULL);
1757  assert((*gubcons)->gubvarsstatus != NULL);
1758 
1759  /* free allocated memory */
1760  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1761  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1762  SCIPfreeBuffer(scip, gubcons);
1763 }
1764 
1765 /** adds variable to given GUB constraint */
1766 static
1768  SCIP* scip, /**< SCIP data structure */
1769  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1770  int var /**< index of given variable in knapsack constraint */
1771  )
1772 {
1773  assert(scip != NULL);
1774  assert(gubcons != NULL);
1775  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1776  assert(gubcons->gubvars != NULL);
1777  assert(gubcons->gubvarsstatus != NULL);
1778  assert(var >= 0);
1779 
1780  /* add variable to GUB constraint */
1781  gubcons->gubvars[gubcons->ngubvars] = var;
1782  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1783  gubcons->ngubvars++;
1784 
1785  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1786  if( gubcons->ngubvars == gubcons->gubvarssize )
1787  {
1788  int newlen;
1789 
1790  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1791  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1792  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1793 
1794  gubcons->gubvarssize = newlen;
1795  }
1796 
1797  return SCIP_OKAY;
1798 }
1799 
1800 /** deletes variable from its current GUB constraint */
1801 static
1803  SCIP* scip, /**< SCIP data structure */
1804  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1805  int var, /**< index of given variable in knapsack constraint */
1806  int gubvarsidx /**< index of the variable in its current GUB constraint */
1807  )
1808 {
1809  assert(scip != NULL);
1810  assert(gubcons != NULL);
1811  assert(var >= 0);
1812  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1813  assert(gubcons->ngubvars >= gubvarsidx+1);
1814  assert(gubcons->gubvars[gubvarsidx] == var);
1815 
1816  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1817  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1818  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1819  gubcons->ngubvars--;
1820 
1821  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1822  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1823  {
1824  int newlen;
1825 
1826  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1827 
1828  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1829  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1830 
1831  gubcons->gubvarssize = newlen;
1832  }
1833 
1834  return SCIP_OKAY;
1835 }
1836 
1837 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1838 static
1840  SCIP* scip, /**< SCIP data structure */
1841  SCIP_GUBSET* gubset, /**< GUB set data structure */
1842  SCIP_VAR** vars, /**< variables in knapsack constraint */
1843  int var, /**< index of given variable in knapsack constraint */
1844  int oldgubcons, /**< index of old GUB constraint of given variable */
1845  int newgubcons /**< index of new GUB constraint of given variable */
1846  )
1848  int oldgubvaridx;
1849  int replacevar;
1850  int j;
1851 
1852  assert(scip != NULL);
1853  assert(gubset != NULL);
1854  assert(var >= 0);
1855  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1856  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1857  assert(oldgubcons != newgubcons);
1858  assert(gubset->gubconssidx[var] == oldgubcons);
1859  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1860  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1861 
1862  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1863 
1864  oldgubvaridx = gubset->gubvarsidx[var];
1865 
1866  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1867  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1868 
1869  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1870  * replacement variable is given by old position of the deleted variable
1871  */
1872  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1873  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1874  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1875 
1876  /* add variable to the end of new GUB constraint */
1877  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1878  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1879 
1880  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1881  gubset->gubconssidx[var] = newgubcons;
1882  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1883 
1884  /* delete old GUB constraint if it became empty */
1885  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1886  {
1887  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1888 #ifdef SCIP_DEBUG
1889  GUBsetPrint(scip, gubset, vars, NULL);
1890 #endif
1891 
1892  /* free old GUB constraint */
1893  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1894 
1895  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1896  if( oldgubcons != gubset->ngubconss-1 )
1897  {
1898  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1899  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1900 
1901  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1902  * replacement GUB is given by old position of the deleted GUB
1903  */
1904  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1905  {
1906  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1907  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1908  }
1909  }
1910 
1911  /* update number of GUB constraints */
1912  gubset->ngubconss--;
1913 
1914  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1915  * (because it was at the end of the GUB constraint array)
1916  */
1917  assert(gubset->gubconssidx[var] == newgubcons
1918  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1919  }
1920 #ifndef NDEBUG
1921  else
1922  assert(gubset->gubconssidx[var] == newgubcons);
1923 #endif
1924 
1925  return SCIP_OKAY;
1926 }
1927 
1928 /** swaps two variables in the same GUB constraint */
1929 static
1930 void GUBsetSwapVars(
1931  SCIP* scip, /**< SCIP data structure */
1932  SCIP_GUBSET* gubset, /**< GUB set data structure */
1933  int var1, /**< first variable to be swapped */
1934  int var2 /**< second variable to be swapped */
1935  )
1936 {
1937  int gubcons;
1938  int var1idx;
1939  GUBVARSTATUS var1status;
1940  int var2idx;
1941  GUBVARSTATUS var2status;
1942 
1943  assert(scip != NULL);
1944  assert(gubset != NULL);
1945 
1946  gubcons = gubset->gubconssidx[var1];
1947  assert(gubcons == gubset->gubconssidx[var2]);
1948 
1949  /* nothing to be done if both variables are the same */
1950  if( var1 == var2 )
1951  return;
1952 
1953  /* swap index and status of variables in GUB constraint */
1954  var1idx = gubset->gubvarsidx[var1];
1955  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1956  var2idx = gubset->gubvarsidx[var2];
1957  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1958 
1959  gubset->gubvarsidx[var1] = var2idx;
1960  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1961  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1962 
1963  gubset->gubvarsidx[var2] = var1idx;
1964  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1965  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1966 }
1967 
1968 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1969 static
1971  SCIP* scip, /**< SCIP data structure */
1972  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1973  int nvars, /**< number of variables in the knapsack constraint */
1974  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1975  SCIP_Longint capacity /**< capacity of knapsack */
1976  )
1977 {
1978  int i;
1979 
1980  assert(scip != NULL);
1981  assert(gubset != NULL);
1982  assert(nvars > 0);
1983  assert(weights != NULL);
1984  assert(capacity >= 0);
1985 
1986  /* allocate memory for GUB set data structures */
1987  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1988  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1989  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1990  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1991  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1992  (*gubset)->ngubconss = nvars;
1993  (*gubset)->nvars = nvars;
1994 
1995  /* initialize the set of GUB constraints */
1996  for( i = 0; i < nvars; i++ )
1997  {
1998  /* assign each variable to a new (trivial) GUB constraint */
1999  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2000  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2001 
2002  /* set status of GUB constraint to initial */
2003  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2004 
2005  (*gubset)->gubconssidx[i] = i;
2006  (*gubset)->gubvarsidx[i] = 0;
2007  assert((*gubset)->gubconss[i]->ngubvars == 1);
2008 
2009  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2010  if( weights[i] > capacity )
2011  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2012  }
2013 
2014  return SCIP_OKAY;
2015 }
2016 
2017 /** frees GUB set data structure */
2018 static
2019 void GUBsetFree(
2020  SCIP* scip, /**< SCIP data structure */
2021  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2022  )
2023 {
2024  int i;
2025 
2026  assert(scip != NULL);
2027  assert(gubset != NULL);
2028  assert((*gubset)->gubconss != NULL);
2029  assert((*gubset)->gubconsstatus != NULL);
2030  assert((*gubset)->gubconssidx != NULL);
2031  assert((*gubset)->gubvarsidx != NULL);
2032 
2033  /* free all GUB constraints */
2034  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2035  {
2036  assert((*gubset)->gubconss[i] != NULL);
2037  GUBconsFree(scip, &(*gubset)->gubconss[i]);
2038  }
2039 
2040  /* free allocated memory */
2041  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2042  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2043  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2044  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2045  SCIPfreeBuffer(scip, gubset);
2046 }
2047 
2048 #ifndef NDEBUG
2049 /** checks whether GUB set data structure is consistent */
2050 static
2052  SCIP* scip, /**< SCIP data structure */
2053  SCIP_GUBSET* gubset, /**< GUB set data structure */
2054  SCIP_VAR** vars /**< variables in the knapsack constraint */
2055  )
2056 {
2057  int i;
2058  int gubconsidx;
2059  int gubvaridx;
2060  SCIP_VAR* var1;
2061  SCIP_VAR* var2;
2062  SCIP_Bool var1negated;
2063  SCIP_Bool var2negated;
2064 
2065  assert(scip != NULL);
2066  assert(gubset != NULL);
2067 
2068  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2069 
2070  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2071  for( i = 0; i < gubset->nvars; i++ )
2072  {
2073  gubconsidx = gubset->gubconssidx[i];
2074  gubvaridx = gubset->gubvarsidx[i];
2075 
2076  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2077  {
2078  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2079  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2080  }
2081  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2082  }
2083 
2084  /* checks for each GUB whether all pairs of its variables have a common clique */
2085  for( i = 0; i < gubset->ngubconss; i++ )
2086  {
2087  int j;
2088 
2089  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2090  {
2091  int k;
2092 
2093  /* get corresponding active problem variable */
2094  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2095  var1negated = FALSE;
2096  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2097 
2098  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2099  {
2100  /* get corresponding active problem variable */
2101  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2102  var2negated = FALSE;
2103  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2104 
2105  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2106  {
2107  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2108  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2109  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2110  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2111  SCIPvarGetName(var1), k,
2112  SCIPvarGetName(var2));
2113  }
2114 
2115  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2116  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2117  }
2118  }
2119  }
2120  SCIPdebugMsg(scip, " --> successful\n");
2121 
2122  return SCIP_OKAY;
2123 }
2124 #endif
2125 
2126 /** calculates a partition of the given set of binary variables into cliques;
2127  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2128  * were assigned to the same clique;
2129  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2130  * the preceding variables was assigned to clique i-1;
2131  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2132  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2133  */
2134 
2135 static
2137  SCIP*const scip, /**< SCIP data structure */
2138  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2139  int const nvars, /**< number of variables in the clique */
2140  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2141  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2142  SCIP_Real* solvals /**< solution values of all given binary variables */
2143  )
2145  SCIP_VAR** tmpvars;
2146  SCIP_VAR** cliquevars;
2147  SCIP_Bool* cliquevalues;
2148  SCIP_Bool* tmpvalues;
2149  int* varseq;
2150  int* sortkeys;
2151  int ncliquevars;
2152  int maxncliquevarscomp;
2153  int nignorevars;
2154  int nvarsused;
2155  int i;
2156 
2157  assert(scip != NULL);
2158  assert(nvars == 0 || vars != NULL);
2159  assert(nvars == 0 || cliquepartition != NULL);
2160  assert(ncliques != NULL);
2161 
2162  if( nvars == 0 )
2163  {
2164  *ncliques = 0;
2165  return SCIP_OKAY;
2166  }
2167 
2168  /* allocate temporary memory for storing the variables of the current clique */
2169  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2170  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2171  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2172  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2173  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2174  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2175 
2176  /* initialize the cliquepartition array with -1 */
2177  /* initialize the tmpvalues array */
2178  for( i = nvars - 1; i >= 0; --i )
2179  {
2180  tmpvalues[i] = TRUE;
2181  cliquepartition[i] = -1;
2182  }
2183 
2184  /* get corresponding active problem variables */
2185  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2186 
2187  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2188  * by nondecreasing number of cliques the variables are in
2189  */
2190  nignorevars = 0;
2191  nvarsused = 0;
2192  for( i = 0; i < nvars; i++ )
2193  {
2194  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2195  {
2196  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2197  varseq[nvars-1-nignorevars] = i;
2198  nignorevars++;
2199  }
2200  else
2201  {
2202  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2203  varseq[nvarsused] = i;
2204  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2205  nvarsused++;
2206  }
2207  }
2208  assert(nvarsused + nignorevars == nvars);
2209 
2210  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2211  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2212 
2213  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2214 
2215  /* calculate the clique partition */
2216  *ncliques = 0;
2217  for( i = 0; i < nvars; ++i )
2218  {
2219  if( cliquepartition[varseq[i]] == -1 )
2220  {
2221  int j;
2222 
2223  /* variable starts a new clique */
2224  cliquepartition[varseq[i]] = *ncliques;
2225  cliquevars[0] = tmpvars[varseq[i]];
2226  cliquevalues[0] = tmpvalues[varseq[i]];
2227  ncliquevars = 1;
2228 
2229  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2230  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2231  */
2232  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2233  {
2234  /* greedily fill up the clique */
2235  for( j = i + 1; j < nvarsused; ++j )
2236  {
2237  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2238  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2239  {
2240  int k;
2241 
2242  /* check if every variable in the actual clique is in clique with the new variable */
2243  for( k = ncliquevars - 1; k >= 0; --k )
2244  {
2245  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2246  cliquevalues[k], TRUE) )
2247  break;
2248  }
2249 
2250  if( k == -1 )
2251  {
2252  /* put the variable into the same clique */
2253  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2254  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2255  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2256  ++ncliquevars;
2257  }
2258  }
2259  }
2260  }
2261 
2262  /* this clique is finished */
2263  ++(*ncliques);
2264  }
2265  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2266 
2267  /* break if we reached the maximal number of comparisons */
2268  if( i * nvars > maxncliquevarscomp )
2269  break;
2270  }
2271  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2272  for( ; i < nvars; ++i )
2273  {
2274  if( cliquepartition[varseq[i]] == -1 )
2275  {
2276  cliquepartition[varseq[i]] = *ncliques;
2277  ++(*ncliques);
2278  }
2279  }
2280 
2281  /* free temporary memory */
2282  SCIPfreeBufferArray(scip, &sortkeys);
2283  SCIPfreeBufferArray(scip, &varseq);
2284  SCIPfreeBufferArray(scip, &tmpvars);
2285  SCIPfreeBufferArray(scip, &tmpvalues);
2286  SCIPfreeBufferArray(scip, &cliquevalues);
2287  SCIPfreeBufferArray(scip, &cliquevars);
2288 
2289  return SCIP_OKAY;
2290 }
2291 
2292 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2293 static
2295  SCIP* scip, /**< SCIP data structure */
2296  SCIP_GUBSET* gubset, /**< GUB set data structure */
2297  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2298  SCIP_Real* solvals /**< solution values of all knapsack variables */
2299  )
2300 {
2301  int* cliquepartition;
2302  int* gubfirstvar;
2303  int ncliques;
2304  int currentgubconsidx;
2305  int newgubconsidx;
2306  int cliqueidx;
2307  int nvars;
2308  int i;
2309 
2310  assert(scip != NULL);
2311  assert(gubset != NULL);
2312  assert(vars != NULL);
2313 
2314  nvars = gubset->nvars;
2315  assert(nvars >= 0);
2316 
2317  /* allocate temporary memory for clique partition */
2318  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2319 
2320  /* compute sophisticated clique partition */
2321  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2322 
2323  /* allocate temporary memory for GUB set data structure */
2324  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2325 
2326  /* translate GUB partition into GUB set data structure */
2327  for( i = 0; i < ncliques; i++ )
2328  {
2329  /* initialize first variable for every GUB */
2330  gubfirstvar[i] = -1;
2331  }
2332  /* move every knapsack variable into GUB defined by clique partition */
2333  for( i = 0; i < nvars; i++ )
2334  {
2335  assert(cliquepartition[i] >= 0);
2336 
2337  cliqueidx = cliquepartition[i];
2338  currentgubconsidx = gubset->gubconssidx[i];
2339  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2340 
2341  /* variable is first element in GUB constraint defined by clique partition */
2342  if( gubfirstvar[cliqueidx] == -1 )
2343  {
2344  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2345  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2346  */
2347  assert(gubset->gubvarsidx[i] == 0);
2348  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2349 
2350  /* remember the first variable found for the current GUB */
2351  gubfirstvar[cliqueidx] = i;
2352  }
2353  /* variable is additional element of GUB constraint defined by clique partition */
2354  else
2355  {
2356  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2357 
2358  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2359  * first variable of this GUB constraint
2360  */
2361  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2362  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2363  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2364 
2365  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2366  }
2367  }
2368 
2369 #ifdef SCIP_DEBUG
2370  /* prints GUB set data structure */
2371  GUBsetPrint(scip, gubset, vars, solvals);
2372 #endif
2373 
2374 #ifndef NDEBUG
2375  /* checks consistency of GUB set data structure */
2376  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2377 #endif
2378 
2379  /* free temporary memory */
2380  SCIPfreeBufferArray(scip, &gubfirstvar);
2381  SCIPfreeBufferArray(scip, &cliquepartition);
2382 
2383  return SCIP_OKAY;
2384 }
2385 
2386 /** 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$
2387  * 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
2388  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2389  */
2390 static
2392  SCIP* scip, /**< SCIP data structure */
2393  SCIP_VAR** vars, /**< variables in knapsack constraint */
2394  int nvars, /**< number of variables in knapsack constraint */
2395  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2396  SCIP_Longint capacity, /**< capacity of knapsack */
2397  SCIP_Real* solvals, /**< solution values of all problem variables */
2398  int* covervars, /**< pointer to store cover variables */
2399  int* noncovervars, /**< pointer to store noncover variables */
2400  int* ncovervars, /**< pointer to store number of cover variables */
2401  int* nnoncovervars, /**< pointer to store number of noncover variables */
2402  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2403  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2404  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2405  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2406  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2407  )
2408 {
2409  SCIP_Longint* transweights;
2410  SCIP_Real* transprofits;
2411  SCIP_Longint transcapacity;
2412  SCIP_Longint fixedonesweight;
2413  SCIP_Longint itemsweight;
2414  SCIP_Bool infeasible;
2415  int* fixedones;
2416  int* fixedzeros;
2417  int* items;
2418  int nfixedones;
2419  int nfixedzeros;
2420  int nitems;
2421  int j;
2422 
2423  assert(scip != NULL);
2424  assert(vars != NULL);
2425  assert(nvars > 0);
2426  assert(weights != NULL);
2427  assert(capacity >= 0);
2428  assert(solvals != NULL);
2429  assert(covervars != NULL);
2430  assert(noncovervars != NULL);
2431  assert(ncovervars != NULL);
2432  assert(nnoncovervars != NULL);
2433  assert(coverweight != NULL);
2434  assert(found != NULL);
2435  assert(ntightened != NULL);
2436  assert(fractional != NULL);
2437 
2438  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2439 
2440  /* allocates temporary memory */
2441  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2442  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2443  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2444  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2445  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2446 
2447  *found = FALSE;
2448  *ncovervars = 0;
2449  *nnoncovervars = 0;
2450  *coverweight = 0;
2451  *fractional = TRUE;
2452 
2453  /* gets the following sets
2454  * N_1 = {j in N : x*_j = 1} (fixedones),
2455  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2456  * N\(N_0 & N_1) (items),
2457  * where x*_j is the solution value of variable x_j
2458  */
2459  nfixedones = 0;
2460  nfixedzeros = 0;
2461  nitems = 0;
2462  fixedonesweight = 0;
2463  itemsweight = 0;
2464  *ntightened = 0;
2465  for( j = 0; j < nvars; j++ )
2466  {
2467  assert(SCIPvarIsBinary(vars[j]));
2468 
2469  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2470  if( weights[j] > capacity )
2471  {
2472  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2473  assert(!infeasible);
2474  (*ntightened)++;
2475  continue;
2476  }
2477 
2478  /* variable x_j has solution value one */
2479  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2480  {
2481  fixedones[nfixedones] = j;
2482  nfixedones++;
2483  fixedonesweight += weights[j];
2484  }
2485  /* variable x_j has solution value zero */
2486  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2487  {
2488  fixedzeros[nfixedzeros] = j;
2489  nfixedzeros++;
2490  }
2491  /* variable x_j has fractional solution value */
2492  else
2493  {
2494  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2495  items[nitems] = j;
2496  nitems++;
2497  itemsweight += weights[j];
2498  }
2499  }
2500  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2501 
2502  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2503  * the separation routine
2504  */
2505  assert(nitems >= 0);
2506  if( nitems == 0 )
2507  {
2508  *fractional = FALSE;
2509  goto TERMINATE;
2510  }
2511  assert(*fractional);
2512 
2513  /* transforms the traditional separation problem (under consideration of the following fixing:
2514  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2515  *
2516  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2517  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2518  * z_j in {0,1}, j in N\(N_0 & N_1)
2519  *
2520  * to a knapsack problem in maximization form by complementing the variables
2521  *
2522  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2523  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2524  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2525  * z_j in {0,1}, j in N\(N_0 & N_1)
2526  */
2527 
2528  /* gets weight and profit of variables in transformed knapsack problem */
2529  for( j = 0; j < nitems; j++ )
2530  {
2531  transweights[j] = weights[items[j]];
2532  transprofits[j] = 1.0 - solvals[items[j]];
2533  }
2534  /* gets capacity of transformed knapsack problem */
2535  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2536 
2537  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2538  * (when variables fixed to zero are not used)
2539  */
2540  if( transcapacity < 0 )
2541  {
2542  assert(!(*found));
2543  goto TERMINATE;
2544  }
2545 
2546  if( modtransused )
2547  {
2548  /* transforms the modified separation problem (under consideration of the following fixing:
2549  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2550  *
2551  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2552  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2553  * z_j in {0,1}, j in N\(N_0 & N_1)
2554  *
2555  * to a knapsack problem in maximization form by complementing the variables
2556  *
2557  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2558  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2559  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2560  * z_j in {0,1}, j in N\(N_0 & N_1)
2561  */
2562 
2563  /* gets weight and profit of variables in modified transformed knapsack problem */
2564  for( j = 0; j < nitems; j++ )
2565  {
2566  transprofits[j] *= weights[items[j]];
2567  assert(SCIPisFeasPositive(scip, transprofits[j]));
2568  }
2569  }
2570 
2571  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2572  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2573  * let z* be the solution, then
2574  * j in C, if z*_j = 0 and
2575  * i in N\C, if z*_j = 1.
2576  */
2577  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2578  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2579  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2580 
2581  /* constructs cover C (sum_{j in C} a_j > a_0) */
2582  for( j = 0; j < *ncovervars; j++ )
2583  {
2584  (*coverweight) += weights[covervars[j]];
2585  }
2586 
2587  /* adds all variables from N_1 to C */
2588  for( j = 0; j < nfixedones; j++ )
2589  {
2590  covervars[*ncovervars] = fixedones[j];
2591  (*ncovervars)++;
2592  (*coverweight) += weights[fixedones[j]];
2593  }
2594 
2595  /* adds all variables from N_0 to N\C */
2596  for( j = 0; j < nfixedzeros; j++ )
2597  {
2598  noncovervars[*nnoncovervars] = fixedzeros[j];
2599  (*nnoncovervars)++;
2600  }
2601  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2602  assert((*coverweight) > capacity);
2603  *found = TRUE;
2604 
2605  TERMINATE:
2606  /* frees temporary memory */
2607  SCIPfreeBufferArray(scip, &items);
2608  SCIPfreeBufferArray(scip, &fixedzeros);
2609  SCIPfreeBufferArray(scip, &fixedones);
2610  SCIPfreeBufferArray(scip, &transprofits);
2611  SCIPfreeBufferArray(scip, &transweights);
2612 
2613  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2614 
2615  return SCIP_OKAY;
2616 }
2617 
2618 #ifndef NDEBUG
2619 /** checks if minweightidx is set correctly
2620  */
2621 static
2623  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2624  SCIP_Longint capacity, /**< capacity of knapsack */
2625  int* covervars, /**< pointer to store cover variables */
2626  int ncovervars, /**< pointer to store number of cover variables */
2627  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2628  int minweightidx, /**< index of variable in cover variables with minimum weight */
2629  int j /**< current index in cover variables */
2630  )
2631 {
2632  SCIP_Longint minweight;
2633  int i;
2634 
2635  assert(weights != NULL);
2636  assert(covervars != NULL);
2637  assert(ncovervars > 0);
2638 
2639  minweight = weights[covervars[minweightidx]];
2640 
2641  /* checks if all cover variables before index j have weight greater than minweight */
2642  for( i = 0; i < j; i++ )
2643  {
2644  assert(weights[covervars[i]] > minweight);
2645  if( weights[covervars[i]] <= minweight )
2646  return FALSE;
2647  }
2648 
2649  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2650  for( i = 0; i < j; i++ )
2651  {
2652  assert(coverweight - weights[covervars[i]] <= capacity);
2653  if( coverweight - weights[covervars[i]] > capacity )
2654  return FALSE;
2655  }
2656  return TRUE;
2657 }
2658 #endif
2659 
2660 
2661 /** 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$,
2662  * 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$
2663  */
2664 static
2666  SCIP* scip, /**< SCIP data structure */
2667  SCIP_Real* solvals, /**< solution values of all problem variables */
2668  int* covervars, /**< cover variables */
2669  int ncovervars, /**< number of cover variables */
2670  int* varsC1, /**< pointer to store variables in C1 */
2671  int* varsC2, /**< pointer to store variables in C2 */
2672  int* nvarsC1, /**< pointer to store number of variables in C1 */
2673  int* nvarsC2 /**< pointer to store number of variables in C2 */
2674  )
2675 {
2676  int j;
2677 
2678  assert(scip != NULL);
2679  assert(ncovervars >= 0);
2680  assert(solvals != NULL);
2681  assert(covervars != NULL);
2682  assert(varsC1 != NULL);
2683  assert(varsC2 != NULL);
2684  assert(nvarsC1 != NULL);
2685  assert(nvarsC2 != NULL);
2686 
2687  *nvarsC1 = 0;
2688  *nvarsC2 = 0;
2689  for( j = 0; j < ncovervars; j++ )
2690  {
2691  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2692 
2693  /* variable has solution value one */
2694  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2695  {
2696  varsC2[*nvarsC2] = covervars[j];
2697  (*nvarsC2)++;
2698  }
2699  /* variable has solution value less than one */
2700  else
2701  {
2702  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2703  varsC1[*nvarsC1] = covervars[j];
2704  (*nvarsC1)++;
2705  }
2706  }
2707  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2708 }
2709 
2710 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2711  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2712  */
2713 static
2715  SCIP* scip, /**< SCIP data structure */
2716  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2717  int* varsC1, /**< pointer to store variables in C1 */
2718  int* varsC2, /**< pointer to store variables in C2 */
2719  int* nvarsC1, /**< pointer to store number of variables in C1 */
2720  int* nvarsC2 /**< pointer to store number of variables in C2 */
2721  )
2723  SCIP_Real* sortkeysC2;
2724  int j;
2725 
2726  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2727  assert(*nvarsC2 > 0);
2728 
2729  /* allocates temporary memory */
2730  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2731 
2732  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2733  for( j = 0; j < *nvarsC2; j++ )
2734  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2735  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2736 
2737  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2738  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2739  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2740  {
2741  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2742  (*nvarsC1)++;
2743  (*nvarsC2)--;
2744  }
2745 
2746  /* frees temporary memory */
2747  SCIPfreeBufferArray(scip, &sortkeysC2);
2748 
2749  return SCIP_OKAY;
2750 }
2751 
2752 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2753 static
2755  SCIP* scip, /**< SCIP data structure */
2756  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2757  int* varsC1, /**< pointer to store variables in C1 */
2758  int* varsC2, /**< pointer to store variables in C2 */
2759  int* nvarsC1, /**< pointer to store number of variables in C1 */
2760  int* nvarsC2 /**< pointer to store number of variables in C2 */
2761  )
2763  SCIP_Real* sortkeysC2;
2764  int j;
2765 
2766  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2767  assert(*nvarsC2 > 0);
2768 
2769  /* allocates temporary memory */
2770  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2771 
2772  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2773  for( j = 0; j < *nvarsC2; j++ )
2774  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2775  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2776 
2777  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2778  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2779  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2780  (*nvarsC1)++;
2781  (*nvarsC2)--;
2782 
2783  /* frees temporary memory */
2784  SCIPfreeBufferArray(scip, &sortkeysC2);
2785 
2786  return SCIP_OKAY;
2787 }
2788 
2789 
2790 /** 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$
2791  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2792  * \f$F = (N \setminus C) \setminus F\f$
2793  */
2794 static
2796  SCIP* scip, /**< SCIP data structure */
2797  SCIP_Real* solvals, /**< solution values of all problem variables */
2798  int* noncovervars, /**< noncover variables */
2799  int nnoncovervars, /**< number of noncover variables */
2800  int* varsF, /**< pointer to store variables in F */
2801  int* varsR, /**< pointer to store variables in R */
2802  int* nvarsF, /**< pointer to store number of variables in F */
2803  int* nvarsR /**< pointer to store number of variables in R */
2804  )
2805 {
2806  int j;
2807 
2808  assert(scip != NULL);
2809  assert(nnoncovervars >= 0);
2810  assert(solvals != NULL);
2811  assert(noncovervars != NULL);
2812  assert(varsF != NULL);
2813  assert(varsR != NULL);
2814  assert(nvarsF != NULL);
2815  assert(nvarsR != NULL);
2816 
2817  *nvarsF = 0;
2818  *nvarsR = 0;
2819 
2820  for( j = 0; j < nnoncovervars; j++ )
2821  {
2822  /* variable has solution value zero */
2823  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2824  {
2825  varsR[*nvarsR] = noncovervars[j];
2826  (*nvarsR)++;
2827  }
2828  /* variable has solution value greater than zero */
2829  else
2830  {
2831  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2832  varsF[*nvarsF] = noncovervars[j];
2833  (*nvarsF)++;
2834  }
2835  }
2836  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2837 }
2838 
2839 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2840  * lifting procedure
2841  */
2842 static
2844  SCIP* scip, /**< SCIP data structure */
2845  SCIP_Real* solvals, /**< solution values of all problem variables */
2846  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2847  int* varsF, /**< pointer to store variables in F */
2848  int* varsC2, /**< pointer to store variables in C2 */
2849  int* varsR, /**< pointer to store variables in R */
2850  int nvarsF, /**< number of variables in F */
2851  int nvarsC2, /**< number of variables in C2 */
2852  int nvarsR /**< number of variables in R */
2853  )
2854 {
2855  SORTKEYPAIR** sortkeypairsF;
2856  SORTKEYPAIR* sortkeypairsFstore;
2857  SCIP_Real* sortkeysC2;
2858  SCIP_Real* sortkeysR;
2859  int j;
2860 
2861  assert(scip != NULL);
2862  assert(solvals != NULL);
2863  assert(weights != NULL);
2864  assert(varsF != NULL);
2865  assert(varsC2 != NULL);
2866  assert(varsR != NULL);
2867  assert(nvarsF >= 0);
2868  assert(nvarsC2 >= 0);
2869  assert(nvarsR >= 0);
2870 
2871  /* allocates temporary memory */
2872  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2873  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2874  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2875  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2876 
2877  /* gets sorting key for variables in F corresponding to the following lifting sequence
2878  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2879  * x*_1 >= x*_2 >= ... >= x*_|F|
2880  * in case of equality uses
2881  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2882  */
2883  for( j = 0; j < nvarsF; j++ )
2884  {
2885  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2886  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2887  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2888  }
2889 
2890  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2891  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2892  */
2893  for( j = 0; j < nvarsC2; j++ )
2894  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2895 
2896  /* gets sorting key for variables in R corresponding to the following lifting sequence
2897  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2898  */
2899  for( j = 0; j < nvarsR; j++ )
2900  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2901 
2902  /* sorts F, C2 and R */
2903  if( nvarsF > 0 )
2904  {
2905  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2906  }
2907  if( nvarsC2 > 0 )
2908  {
2909  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2910  }
2911  if( nvarsR > 0)
2912  {
2913  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2914  }
2915 
2916  /* frees temporary memory */
2917  SCIPfreeBufferArray(scip, &sortkeysR);
2918  SCIPfreeBufferArray(scip, &sortkeysC2);
2919  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2920  SCIPfreeBufferArray(scip, &sortkeypairsF);
2921 
2922  return SCIP_OKAY;
2923 }
2924 
2925 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2926  * for the sequential GUB wise lifting procedure
2927  */
2928 static
2930  SCIP* scip, /**< SCIP data structure */
2931  SCIP_GUBSET* gubset, /**< GUB set data structure */
2932  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2933  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2934  int* varsC1, /**< variables in C1 */
2935  int* varsC2, /**< variables in C2 */
2936  int* varsF, /**< variables in F */
2937  int* varsR, /**< variables in R */
2938  int nvarsC1, /**< number of variables in C1 */
2939  int nvarsC2, /**< number of variables in C2 */
2940  int nvarsF, /**< number of variables in F */
2941  int nvarsR, /**< number of variables in R */
2942  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2943  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2944  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2945  int* gubconsGR, /**< pointer to store GUBs in GR */
2946  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2947  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2948  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2949  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2950  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2951  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2952  )
2953 {
2954  SORTKEYPAIR** sortkeypairsGFC1;
2955  SORTKEYPAIR* sortkeypairsGFC1store;
2956  SCIP_Real* sortkeysC1;
2957  SCIP_Real* sortkeysC2;
2958  SCIP_Real* sortkeysR;
2959  int* nC1varsingubcons;
2960  int var;
2961  int gubconsidx;
2962  int varidx;
2963  int ngubconss;
2964  int ngubconsGOC1;
2965  int targetvar;
2966 #ifndef NDEBUG
2967  int nvarsprocessed = 0;
2968 #endif
2969  int i;
2970  int j;
2971 
2972 #if GUBSPLITGNC1GUBS
2973  SCIP_Bool gubconswithF;
2974  int origngubconss;
2975  origngubconss = gubset->ngubconss;
2976 #endif
2977 
2978  assert(scip != NULL);
2979  assert(gubset != NULL);
2980  assert(solvals != NULL);
2981  assert(weights != NULL);
2982  assert(varsC1 != NULL);
2983  assert(varsC2 != NULL);
2984  assert(varsF != NULL);
2985  assert(varsR != NULL);
2986  assert(nvarsC1 > 0);
2987  assert(nvarsC2 >= 0);
2988  assert(nvarsF >= 0);
2989  assert(nvarsR >= 0);
2990  assert(gubconsGC1 != NULL);
2991  assert(gubconsGC2 != NULL);
2992  assert(gubconsGFC1 != NULL);
2993  assert(gubconsGR != NULL);
2994  assert(ngubconsGC1 != NULL);
2995  assert(ngubconsGC2 != NULL);
2996  assert(ngubconsGFC1 != NULL);
2997  assert(ngubconsGR != NULL);
2998  assert(maxgubvarssize != NULL);
2999 
3000  ngubconss = gubset->ngubconss;
3001  ngubconsGOC1 = 0;
3002 
3003  /* GUBs are categorized into different types according to the variables in volved
3004  * - GOC1: involves variables in C1 only -- no C2, R, F
3005  * - GNC1: involves variables in C1 and F (and R) -- no C2
3006  * - GF: involves variables in F (and R) only -- no C1, C2
3007  * - GC2: involves variables in C2 only -- no C1, R, F
3008  * - GR: involves variables in R only -- no C1, C2, F
3009  * which requires splitting GUBs in case they include variable in F and R.
3010  *
3011  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3012  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3013  * - second ordering level is
3014  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3015  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3016  * GR: non-increasing max{ a_k : k in GR_j}
3017  *
3018  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3019  * - GC1: GUBs of category GOC1 and GNC1
3020  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3021  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3022  */
3023 
3024  /* allocates temporary memory */
3025  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3026  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3027  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3028 
3029  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3030  * - F: non-increasing x*_j and non-increasing a_j in case of equality
3031  * - C2: non-increasing a_j
3032  * - R: non-increasing a_j
3033  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3034  */
3035 
3036  /* gets sorting key for variables in C1 corresponding to the following ordering
3037  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3038  */
3039  for( j = 0; j < nvarsC1; j++ )
3040  {
3041  /* gets sortkeys */
3042  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3043 
3044  /* update status of variable in its gub constraint */
3045  gubconsidx = gubset->gubconssidx[varsC1[j]];
3046  varidx = gubset->gubvarsidx[varsC1[j]];
3047  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3048  }
3049 
3050  /* gets sorting key for variables in F corresponding to the following ordering
3051  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3052  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3053  * and updates status of each variable in F in GUB set data structure
3054  */
3055  for( j = 0; j < nvarsF; j++ )
3056  {
3057  /* update status of variable in its gub constraint */
3058  gubconsidx = gubset->gubconssidx[varsF[j]];
3059  varidx = gubset->gubvarsidx[varsF[j]];
3060  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3061  }
3062 
3063  /* gets sorting key for variables in C2 corresponding to the following ordering
3064  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3065  * and updates status of each variable in F in GUB set data structure
3066  */
3067  for( j = 0; j < nvarsC2; j++ )
3068  {
3069  /* gets sortkeys */
3070  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3071 
3072  /* update status of variable in its gub constraint */
3073  gubconsidx = gubset->gubconssidx[varsC2[j]];
3074  varidx = gubset->gubvarsidx[varsC2[j]];
3075  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3076  }
3077 
3078  /* gets sorting key for variables in R corresponding to the following ordering
3079  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3080  * and updates status of each variable in F in GUB set data structure
3081  */
3082  for( j = 0; j < nvarsR; j++ )
3083  {
3084  /* gets sortkeys */
3085  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3086 
3087  /* update status of variable in its gub constraint */
3088  gubconsidx = gubset->gubconssidx[varsR[j]];
3089  varidx = gubset->gubvarsidx[varsR[j]];
3090  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3091  }
3092 
3093  /* sorts C1, F, C2 and R */
3094  assert(nvarsC1 > 0);
3095  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3096 
3097  if( nvarsC2 > 0 )
3098  {
3099  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3100  }
3101  if( nvarsR > 0)
3102  {
3103  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3104  }
3105 
3106  /* frees temporary memory */
3107  SCIPfreeBufferArray(scip, &sortkeysR);
3108  SCIPfreeBufferArray(scip, &sortkeysC2);
3109  SCIPfreeBufferArray(scip, &sortkeysC1);
3110 
3111  /* allocate and initialize temporary memory for sorting GUB constraints */
3112  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3113  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3114  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3115  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3116  for( i = 0; i < ngubconss; i++)
3117  {
3118  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3119  sortkeypairsGFC1[i]->key1 = 0.0;
3120  sortkeypairsGFC1[i]->key2 = 0.0;
3121  }
3122  *ngubconsGC1 = 0;
3123  *ngubconsGC2 = 0;
3124  *ngubconsGFC1 = 0;
3125  *ngubconsGR = 0;
3126  *ngubconscapexceed = 0;
3127  *maxgubvarssize = 0;
3128 
3129 #ifndef NDEBUG
3130  for( i = 0; i < gubset->ngubconss; i++ )
3131  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3132 #endif
3133 
3134  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3135  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3136  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3137  * non-increasing number of variables in F, and
3138  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3139  */
3140  for( i = 0; i < nvarsC1; i++ )
3141  {
3142  int nvarsC1capexceed;
3143 
3144  nvarsC1capexceed = 0;
3145 
3146  var = varsC1[i];
3147  gubconsidx = gubset->gubconssidx[var];
3148  varidx = gubset->gubvarsidx[var];
3149 
3150  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3151  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3152 
3153  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3154  * note that variables in C1 are already sorted by non-decreasing weigth
3155  */
3156  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3157  GUBsetSwapVars(scip, gubset, var, targetvar);
3158  nC1varsingubcons[gubconsidx]++;
3159 
3160  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3161  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3162  {
3163  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3164  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3165  continue;
3166  }
3167 
3168  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3169  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3170  */
3171 #if GUBSPLITGNC1GUBS
3172  gubconswithF = FALSE;
3173 #endif
3174  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3175  {
3176  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3177 
3178  /* C1-variable: update number of C1/capacity exceeding variables */
3179  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3180  {
3181  nvarsC1capexceed++;
3182 #ifndef NDEBUG
3183  nvarsprocessed++;
3184 #endif
3185  }
3186  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3187  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3188  {
3189 #if GUBSPLITGNC1GUBS
3190  gubconswithF = TRUE;
3191 #endif
3192  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3193 
3194  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3195  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3196  }
3197  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3198  {
3199  nvarsC1capexceed++;
3200  }
3201  else
3202  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3203  }
3204 
3205  /* update set of GC1 GUBs */
3206  gubconsGC1[*ngubconsGC1] = gubconsidx;
3207  (*ngubconsGC1)++;
3208 
3209  /* update maximum size of all GUB constraints */
3210  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3211  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3212 
3213  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3214  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3215  {
3216  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3217  ngubconsGOC1++;
3218  }
3219  else
3220  {
3221 #if GUBSPLITGNC1GUBS
3222  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3223  if( !gubconswithF )
3224  {
3225  GUBVARSTATUS movevarstatus;
3226 
3227  assert(gubset->ngubconss < gubset->nvars);
3228 
3229  /* create a new GUB for GR part of splitting */
3230  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3231  gubset->ngubconss++;
3232  ngubconss = gubset->ngubconss;
3233 
3234  /* fill GR with R variables in current GUB */
3235  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3236  {
3237  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3238  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3239  {
3240  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3241  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3242  gubconsidx, ngubconss-1) );
3243  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3244  movevarstatus;
3245  }
3246  }
3247 
3248  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3249  ngubconsGOC1++;
3250 
3251  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3252  gubconsGR[*ngubconsGR] = ngubconss-1;
3253  (*ngubconsGR)++;
3254  }
3255  /* variables in C1, F, and maybe R: GNC1 GUB */
3256  else
3257  {
3258  assert(gubconswithF);
3259 
3260  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3261  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3262  (*ngubconsGFC1)++;
3263  }
3264 #else
3265  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3266  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3267  (*ngubconsGFC1)++;
3268 #endif
3269  }
3270  }
3271 
3272  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3273  * are already sorted correctly
3274  */
3275  for( i = 0; i < nvarsC2; i++ )
3276  {
3277  var = varsC2[i];
3278  gubconsidx = gubset->gubconssidx[var];
3279  varidx = gubset->gubvarsidx[var];
3280 
3281  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3282  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3283  assert(varidx == 0);
3284  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3285  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3286 
3287  /* set status of GC2 GUB */
3288  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3289 
3290  /* update group of GC2 GUBs */
3291  gubconsGC2[*ngubconsGC2] = gubconsidx;
3292  (*ngubconsGC2)++;
3293 
3294  /* update maximum size of all GUB constraints */
3295  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3296  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3297 
3298 #ifndef NDEBUG
3299  nvarsprocessed++;
3300 #endif
3301  }
3302 
3303  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3304  * non-increasing number of variables in F, and
3305  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3306  */
3307  for( i = 0; i < nvarsF; i++ )
3308  {
3309  var = varsF[i];
3310  gubconsidx = gubset->gubconssidx[var];
3311  varidx = gubset->gubvarsidx[var];
3312 
3313  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3314  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3315 
3316 #ifndef NDEBUG
3317  nvarsprocessed++;
3318 #endif
3319 
3320  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3321  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3322  {
3323  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3324  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3325  continue;
3326  }
3327 
3328  /* set status of GF GUB */
3329  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3330 
3331  /* update sorting key of corresponding GFC1 GUB */
3332  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3333  {
3334  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3335  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3336 
3337  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3338  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3339  {
3340  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3341 
3342  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3343  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3344  }
3345  }
3346 
3347  /* update set of GFC1 GUBs */
3348  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3349  (*ngubconsGFC1)++;
3350 
3351  /* update maximum size of all GUB constraints */
3352  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3353  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3354  }
3355 
3356  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3357  * correctly
3358  */
3359  for( i = 0; i < nvarsR; i++ )
3360  {
3361  var = varsR[i];
3362  gubconsidx = gubset->gubconssidx[var];
3363  varidx = gubset->gubvarsidx[var];
3364 
3365  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3366  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3367 
3368 #ifndef NDEBUG
3369  nvarsprocessed++;
3370 #endif
3371 
3372  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3373  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3374  {
3375  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3376  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3377  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3378  continue;
3379  }
3380 
3381  /* set status of GR GUB */
3382  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3383 
3384  /* update set of GR GUBs */
3385  gubconsGR[*ngubconsGR] = gubconsidx;
3386  (*ngubconsGR)++;
3387 
3388  /* update maximum size of all GUB constraints */
3389  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3390  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3391  }
3392  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3393 
3394  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3395  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3396  assert(*ngubconscapexceed >= 0);
3397 #ifndef NDEBUG
3398  {
3399  int check;
3400 
3401  check = 0;
3402 
3403  /* remaining not handled GUBs should only contain capacity exceeding variables */
3404  for( i = 0; i < ngubconss; i++ )
3405  {
3406  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3407  check++;
3408  }
3409  assert(check == *ngubconscapexceed);
3410  }
3411 #endif
3412 
3413  /* sort GFCI GUBs according to computed sorting keys */
3414  if( (*ngubconsGFC1) > 0 )
3415  {
3416  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3417  }
3418 
3419  /* free temporary memory */
3420 #if GUBSPLITGNC1GUBS
3421  ngubconss = origngubconss;
3422 #endif
3423  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3424  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3425  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3426 
3427  return SCIP_OKAY;
3428 }
3429 
3430 /** enlarges minweight table to at least the given length */
3431 static
3433  SCIP* scip, /**< SCIP data structure */
3434  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3435  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3436  int* minweightssize, /**< pointer to current size of minweights table */
3437  int newlen /**< new length of minweights table */
3438  )
3439 {
3440  int j;
3441 
3442  assert(minweightsptr != NULL);
3443  assert(*minweightsptr != NULL);
3444  assert(minweightslen != NULL);
3445  assert(*minweightslen >= 0);
3446  assert(minweightssize != NULL);
3447  assert(*minweightssize >= 0);
3448 
3449  if( newlen > *minweightssize )
3450  {
3451  int newsize;
3452 
3453  /* reallocate table memory */
3454  newsize = SCIPcalcMemGrowSize(scip, newlen);
3455  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3456  *minweightssize = newsize;
3457  }
3458  assert(newlen <= *minweightssize);
3459 
3460  /* initialize new elements */
3461  for( j = *minweightslen; j < newlen; ++j )
3462  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3463  *minweightslen = newlen;
3464 
3465  return SCIP_OKAY;
3466 }
3467 
3468 /** lifts given inequality
3469  * sum_{j in M_1} x_j <= alpha_0
3470  * valid for
3471  * 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 }
3472  * to a valid inequality
3473  * 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
3474  * <= alpha_0 + sum_{j in M_2} alpha_j
3475  * for
3476  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3477  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3478  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3479  * extended weight inequalities.
3480  */
3481 static
3483  SCIP* scip, /**< SCIP data structure */
3484  SCIP_VAR** vars, /**< variables in knapsack constraint */
3485  int nvars, /**< number of variables in knapsack constraint */
3486  int ntightened, /**< number of variables with tightened upper bound */
3487  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3488  SCIP_Longint capacity, /**< capacity of knapsack */
3489  SCIP_Real* solvals, /**< solution values of all problem variables */
3490  int* varsM1, /**< variables in M_1 */
3491  int* varsM2, /**< variables in M_2 */
3492  int* varsF, /**< variables in F */
3493  int* varsR, /**< variables in R */
3494  int nvarsM1, /**< number of variables in M_1 */
3495  int nvarsM2, /**< number of variables in M_2 */
3496  int nvarsF, /**< number of variables in F */
3497  int nvarsR, /**< number of variables in R */
3498  int alpha0, /**< rights hand side of given valid inequality */
3499  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3500  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3501  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3502  )
3503 {
3504  SCIP_Longint* minweights;
3505  SCIP_Real* sortkeys;
3506  SCIP_Longint fixedonesweight;
3507  int minweightssize;
3508  int minweightslen;
3509  int j;
3510  int w;
3511 
3512  assert(scip != NULL);
3513  assert(vars != NULL);
3514  assert(nvars >= 0);
3515  assert(weights != NULL);
3516  assert(capacity >= 0);
3517  assert(solvals != NULL);
3518  assert(varsM1 != NULL);
3519  assert(varsM2 != NULL);
3520  assert(varsF != NULL);
3521  assert(varsR != NULL);
3522  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3523  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3524  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3525  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3526  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3527  assert(alpha0 >= 0);
3528  assert(liftcoefs != NULL);
3529  assert(cutact != NULL);
3530  assert(liftrhs != NULL);
3531 
3532  /* allocates temporary memory */
3533  minweightssize = nvarsM1 + 1;
3534  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3535  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3536 
3537  /* initializes data structures */
3538  BMSclearMemoryArray(liftcoefs, nvars);
3539  *cutact = 0.0;
3540 
3541  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3542  * and calculates activity of the current valid inequality
3543  */
3544  for( j = 0; j < nvarsM1; j++ )
3545  {
3546  assert(liftcoefs[varsM1[j]] == 0);
3547  liftcoefs[varsM1[j]] = 1;
3548  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3549  (*cutact) += solvals[varsM1[j]];
3550  }
3551 
3552  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3553 
3554  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3555  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3556  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3557  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3558  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3559  */
3560  minweights[0] = 0;
3561  for( w = 1; w <= nvarsM1; w++ )
3562  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3563  minweightslen = nvarsM1 + 1;
3564 
3565  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3566  fixedonesweight = 0;
3567  for( j = 0; j < nvarsM2; j++ )
3568  fixedonesweight += weights[varsM2[j]];
3569  assert(fixedonesweight >= 0);
3570 
3571  /* initializes right hand side of lifted valid inequality */
3572  *liftrhs = alpha0;
3573 
3574  /* sequentially up-lifts all variables in F: */
3575  for( j = 0; j < nvarsF; j++ )
3576  {
3577  SCIP_Longint weight;
3578  int liftvar;
3579  int liftcoef;
3580  int z;
3581 
3582  liftvar = varsF[j];
3583  weight = weights[liftvar];
3584  assert(liftvar >= 0 && liftvar < nvars);
3585  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3586  assert(weight > 0);
3587 
3588  /* knapsack problem is infeasible:
3589  * sets z = 0
3590  */
3591  if( capacity - fixedonesweight - weight < 0 )
3592  {
3593  z = 0;
3594  }
3595  /* knapsack problem is feasible:
3596  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3597  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3598  */
3599  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3600  {
3601  z = *liftrhs;
3602  }
3603  /* knapsack problem is feasible:
3604  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3605  */
3606  else
3607  {
3608  int left;
3609  int right;
3610  int middle;
3611 
3612  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3613  left = 0;
3614  right = (*liftrhs) + 1;
3615  while( left < right - 1 )
3616  {
3617  middle = (left + right) / 2;
3618  assert(0 <= middle && middle < minweightslen);
3619  if( minweights[middle] <= capacity - fixedonesweight - weight )
3620  left = middle;
3621  else
3622  right = middle;
3623  }
3624  assert(left == right - 1);
3625  assert(0 <= left && left < minweightslen);
3626  assert(minweights[left] <= capacity - fixedonesweight - weight );
3627  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3628 
3629  /* now z = left */
3630  z = left;
3631  assert(z <= *liftrhs);
3632  }
3633 
3634  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3635  liftcoef = (*liftrhs) - z;
3636  liftcoefs[liftvar] = liftcoef;
3637  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3638 
3639  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3640  if( liftcoef == 0 )
3641  continue;
3642 
3643  /* updates activity of current valid inequality */
3644  (*cutact) += liftcoef * solvals[liftvar];
3645 
3646  /* enlarges current minweight table:
3647  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3648  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3649  * and sets minweights_i[w] = infinity for
3650  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3651  */
3652  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3653 
3654  /* updates minweight table: minweight_i+1[w] =
3655  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3656  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3657  */
3658  for( w = minweightslen - 1; w >= 0; w-- )
3659  {
3660  SCIP_Longint min;
3661  if( w < liftcoef )
3662  {
3663  min = MIN(minweights[w], weight);
3664  minweights[w] = min;
3665  }
3666  else
3667  {
3668  assert(w >= liftcoef);
3669  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3670  minweights[w] = min;
3671  }
3672  }
3673  }
3674  assert(minweights[0] == 0);
3675 
3676  /* sequentially down-lifts all variables in M_2: */
3677  for( j = 0; j < nvarsM2; j++ )
3678  {
3679  SCIP_Longint weight;
3680  int liftvar;
3681  int liftcoef;
3682  int left;
3683  int right;
3684  int middle;
3685  int z;
3686 
3687  liftvar = varsM2[j];
3688  weight = weights[liftvar];
3689  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3690  assert(liftvar >= 0 && liftvar < nvars);
3691  assert(weight > 0);
3692 
3693  /* uses binary search to find
3694  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3695  */
3696  left = 0;
3697  right = minweightslen;
3698  while( left < right - 1 )
3699  {
3700  middle = (left + right) / 2;
3701  assert(0 <= middle && middle < minweightslen);
3702  if( minweights[middle] <= capacity - fixedonesweight + weight )
3703  left = middle;
3704  else
3705  right = middle;
3706  }
3707  assert(left == right - 1);
3708  assert(0 <= left && left < minweightslen);
3709  assert(minweights[left] <= capacity - fixedonesweight + weight );
3710  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3711 
3712  /* now z = left */
3713  z = left;
3714  assert(z >= *liftrhs);
3715 
3716  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3717  liftcoef = z - (*liftrhs);
3718  liftcoefs[liftvar] = liftcoef;
3719  assert(liftcoef >= 0);
3720 
3721  /* updates sum of weights of variables fixed to one */
3722  fixedonesweight -= weight;
3723 
3724  /* updates right-hand side of current valid inequality */
3725  (*liftrhs) += liftcoef;
3726  assert(*liftrhs >= alpha0);
3727 
3728  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3729  if( liftcoef == 0 )
3730  continue;
3731 
3732  /* updates activity of current valid inequality */
3733  (*cutact) += liftcoef * solvals[liftvar];
3734 
3735  /* enlarges current minweight table:
3736  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3737  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3738  * and sets minweights_i[w] = infinity for
3739  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3740  */
3741  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3742 
3743  /* updates minweight table: minweight_i+1[w] =
3744  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3745  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3746  */
3747  for( w = minweightslen - 1; w >= 0; w-- )
3748  {
3749  SCIP_Longint min;
3750  if( w < liftcoef )
3751  {
3752  min = MIN(minweights[w], weight);
3753  minweights[w] = min;
3754  }
3755  else
3756  {
3757  assert(w >= liftcoef);
3758  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3759  minweights[w] = min;
3760  }
3761  }
3762  }
3763  assert(fixedonesweight == 0);
3764  assert(*liftrhs >= alpha0);
3765 
3766  /* sequentially up-lifts all variables in R: */
3767  for( j = 0; j < nvarsR; j++ )
3768  {
3769  SCIP_Longint weight;
3770  int liftvar;
3771  int liftcoef;
3772  int z;
3773 
3774  liftvar = varsR[j];
3775  weight = weights[liftvar];
3776  assert(liftvar >= 0 && liftvar < nvars);
3777  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3778  assert(weight > 0);
3779  assert(capacity - weight >= 0);
3780  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3781 
3782  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3783  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3784  */
3785  if( minweights[*liftrhs] <= capacity - weight )
3786  {
3787  z = *liftrhs;
3788  }
3789  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3790  */
3791  else
3792  {
3793  int left;
3794  int right;
3795  int middle;
3796 
3797  left = 0;
3798  right = (*liftrhs) + 1;
3799  while( left < right - 1)
3800  {
3801  middle = (left + right) / 2;
3802  assert(0 <= middle && middle < minweightslen);
3803  if( minweights[middle] <= capacity - weight )
3804  left = middle;
3805  else
3806  right = middle;
3807  }
3808  assert(left == right - 1);
3809  assert(0 <= left && left < minweightslen);
3810  assert(minweights[left] <= capacity - weight );
3811  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3812 
3813  /* now z = left */
3814  z = left;
3815  assert(z <= *liftrhs);
3816  }
3817 
3818  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3819  liftcoef = (*liftrhs) - z;
3820  liftcoefs[liftvar] = liftcoef;
3821  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3822 
3823  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3824  if( liftcoef == 0 )
3825  continue;
3826 
3827  /* updates activity of current valid inequality */
3828  (*cutact) += liftcoef * solvals[liftvar];
3829 
3830  /* updates minweight table: minweight_i+1[w] =
3831  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3832  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3833  */
3834  for( w = *liftrhs; w >= 0; w-- )
3835  {
3836  SCIP_Longint min;
3837  if( w < liftcoef )
3838  {
3839  min = MIN(minweights[w], weight);
3840  minweights[w] = min;
3841  }
3842  else
3843  {
3844  assert(w >= liftcoef);
3845  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3846  minweights[w] = min;
3847  }
3848  }
3849  }
3850 
3851  /* frees temporary memory */
3852  SCIPfreeBufferArray(scip, &sortkeys);
3853  SCIPfreeBufferArray(scip, &minweights);
3854 
3855  return SCIP_OKAY;
3856 }
3857 
3858 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3859 static
3861  SCIP_Longint val1, /**< first value to add */
3862  SCIP_Longint val2 /**< second value to add */
3863  )
3864 {
3865  assert(val1 >= 0);
3866  assert(val2 >= 0);
3867 
3868  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3869  return SCIP_LONGINT_MAX;
3870  else
3871  {
3872  assert(val1 <= SCIP_LONGINT_MAX - val2);
3873  return (val1 + val2);
3874  }
3875 }
3876 
3877 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3878 static
3880  SCIP_Longint* minweights, /**< minweight table to compute */
3881  SCIP_Longint* finished, /**< given finished table */
3882  SCIP_Longint* unfinished, /**< given unfinished table */
3883  int minweightslen /**< length of minweight, finished, and unfinished tables */
3884  )
3885 {
3886  int w1;
3887  int w2;
3888 
3889  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3890  * note that finished and unfished arrays sorted by non-decreasing weight
3891  */
3892 
3893  /* initialize minweight with w2 = 0 */
3894  w2 = 0;
3895  assert(unfinished[w2] == 0);
3896  for( w1 = 0; w1 < minweightslen; w1++ )
3897  minweights[w1] = finished[w1];
3898 
3899  /* consider w2 = 1, ..., minweightslen-1 */
3900  for( w2 = 1; w2 < minweightslen; w2++ )
3901  {
3902  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3903  break;
3904 
3905  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3906  {
3907  SCIP_Longint temp;
3908 
3909  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3910  if( temp <= minweights[w1+w2] )
3911  minweights[w1+w2] = temp;
3912  }
3913  }
3914 }
3915 
3916 /** lifts given inequality
3917  * sum_{j in C_1} x_j <= alpha_0
3918  * valid for
3919  * 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;
3920  * sum_{j in Q_i} x_j <= 1, forall i in I }
3921  * to a valid inequality
3922  * 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
3923  * <= alpha_0 + sum_{j in C_2} alpha_j
3924  * for
3925  * 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 };
3926  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3927  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3928  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3929  */
3930 static
3932  SCIP* scip, /**< SCIP data structure */
3933  SCIP_GUBSET* gubset, /**< GUB set data structure */
3934  SCIP_VAR** vars, /**< variables in knapsack constraint */
3935  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3936  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3937  SCIP_Longint capacity, /**< capacity of knapsack */
3938  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3939  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3940  int* gubconsGC2, /**< GUBs in GC2 */
3941  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3942  int* gubconsGR, /**< GUBs in GR */
3943  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3944  int ngubconsGC2, /**< number of GUBs in GC2 */
3945  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3946  int ngubconsGR, /**< number of GUBs in GR */
3947  int alpha0, /**< rights hand side of given valid inequality */
3948  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3949  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3950  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3951  int maxgubvarssize /**< maximal size of GUB constraints */
3952  )
3953 {
3954  SCIP_Longint* minweights;
3955  SCIP_Longint* finished;
3956  SCIP_Longint* unfinished;
3957  int* gubconsGOC1;
3958  int* gubconsGNC1;
3959  int* liftgubvars;
3960  SCIP_Longint fixedonesweight;
3961  SCIP_Longint weight;
3962  SCIP_Longint weightdiff1;
3963  SCIP_Longint weightdiff2;
3964  SCIP_Longint min;
3965  int minweightssize;
3966  int minweightslen;
3967  int nvars;
3968  int varidx;
3969  int liftgubconsidx;
3970  int liftvar;
3971  int sumliftcoef;
3972  int liftcoef;
3973  int ngubconsGOC1;
3974  int ngubconsGNC1;
3975  int left;
3976  int right;
3977  int middle;
3978  int nliftgubvars;
3979  int tmplen;
3980  int tmpsize;
3981  int j;
3982  int k;
3983  int w;
3984  int z;
3985 #ifndef NDEBUG
3986  int ngubconss;
3987  int nliftgubC1;
3988 
3989  assert(gubset != NULL);
3990  ngubconss = gubset->ngubconss;
3991 #else
3992  assert(gubset != NULL);
3993 #endif
3994 
3995  nvars = gubset->nvars;
3996 
3997  assert(scip != NULL);
3998  assert(vars != NULL);
3999  assert(nvars >= 0);
4000  assert(weights != NULL);
4001  assert(capacity >= 0);
4002  assert(solvals != NULL);
4003  assert(gubconsGC1 != NULL);
4004  assert(gubconsGC2 != NULL);
4005  assert(gubconsGFC1 != NULL);
4006  assert(gubconsGR != NULL);
4007  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4008  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4009  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4010  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4011  assert(alpha0 >= 0);
4012  assert(liftcoefs != NULL);
4013  assert(cutact != NULL);
4014  assert(liftrhs != NULL);
4015 
4016  minweightssize = ngubconsGC1+1;
4017 
4018  /* allocates temporary memory */
4019  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4020  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4021  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4022  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4023  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4024  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4025 
4026  /* initializes data structures */
4027  BMSclearMemoryArray(liftcoefs, nvars);
4028  *cutact = 0.0;
4029 
4030  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4031  * valid inequality
4032  */
4033  ngubconsGOC1 = 0;
4034  ngubconsGNC1 = 0;
4035  for( j = 0; j < ngubconsGC1; j++ )
4036  {
4037  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4038  {
4039  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4040  ngubconsGOC1++;
4041  }
4042  else
4043  {
4044  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4045  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4046  ngubconsGNC1++;
4047  }
4048  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4049  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4050  {
4051  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4052  assert(varidx >= 0 && varidx < nvars);
4053  assert(liftcoefs[varidx] == 0);
4054 
4055  liftcoefs[varidx] = 1;
4056  (*cutact) += solvals[varidx];
4057  }
4058  assert(k >= 1);
4059  }
4060  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4061  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4062 
4063  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4064  * - finished_i[w] =
4065  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4066  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4067  * sum_{j in Q_k} x_j <= 1
4068  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4069  * - unfinished_i[w] =
4070  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4071  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4072  * sum_{j in Q_k} x_j <= 1
4073  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4074  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4075  */
4076 
4077  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4078  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4079  * 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
4080  * comes from the first variable in the GUB
4081  */
4082  assert(ngubconsGOC1 <= ngubconsGC1);
4083  finished[0] = 0;
4084  for( w = 1; w <= ngubconsGOC1; w++ )
4085  {
4086  liftgubconsidx = gubconsGOC1[w-1];
4087 
4088  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4089  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4090 
4091  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4092 
4093  assert(varidx >= 0 && varidx < nvars);
4094  assert(liftcoefs[varidx] == 1);
4095 
4096  min = weights[varidx];
4097  finished[w] = finished[w-1] + min;
4098 
4099 #ifndef NDEBUG
4100  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4101  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4102  {
4103  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4104  assert(varidx >= 0 && varidx < nvars);
4105  assert(liftcoefs[varidx] == 1);
4106  assert(weights[varidx] >= min);
4107  }
4108 #endif
4109  }
4110  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4111  finished[w] = SCIP_LONGINT_MAX;
4112 
4113  /* initialize unfinished table; note that variables in GNC1 GUBs
4114  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4115  * 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
4116  * comes from the first variable in the GUB
4117  */
4118  assert(ngubconsGNC1 <= ngubconsGC1);
4119  unfinished[0] = 0;
4120  for( w = 1; w <= ngubconsGNC1; w++ )
4121  {
4122  liftgubconsidx = gubconsGNC1[w-1];
4123 
4124  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4125  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4126 
4127  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4128 
4129  assert(varidx >= 0 && varidx < nvars);
4130  assert(liftcoefs[varidx] == 1);
4131 
4132  min = weights[varidx];
4133  unfinished[w] = unfinished[w-1] + min;
4134 
4135 #ifndef NDEBUG
4136  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4137  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4138  {
4139  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4140  assert(varidx >= 0 && varidx < nvars);
4141  assert(liftcoefs[varidx] == 1);
4142  assert(weights[varidx] >= min );
4143  }
4144 #endif
4145  }
4146  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4147  unfinished[w] = SCIP_LONGINT_MAX;
4148 
4149  /* initialize minweights table; note that variables in GC1 GUBs
4150  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4151  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4152  * consuming) because is it has to be build using weights from C1 only.
4153  */
4154  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4155  minweights[0] = 0;
4156  for( w = 1; w <= ngubconsGC1; w++ )
4157  {
4158  liftgubconsidx = gubconsGC1[w-1];
4159 
4160  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4161  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4162  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4163 
4164  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4165 
4166  assert(varidx >= 0 && varidx < nvars);
4167  assert(liftcoefs[varidx] == 1);
4168 
4169  min = weights[varidx];
4170  minweights[w] = minweights[w-1] + min;
4171 
4172 #ifndef NDEBUG
4173  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4174  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4175  {
4176  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4177  assert(varidx >= 0 && varidx < nvars);
4178  assert(liftcoefs[varidx] == 1);
4179  assert(weights[varidx] >= min);
4180  }
4181 #endif
4182  }
4183  minweightslen = ngubconsGC1 + 1;
4184 
4185  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4186  fixedonesweight = 0;
4187  for( j = 0; j < ngubconsGC2; j++ )
4188  {
4189  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4190 
4191  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4192  assert(varidx >= 0 && varidx < nvars);
4193  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4194 
4195  fixedonesweight += weights[varidx];
4196  }
4197  assert(fixedonesweight >= 0);
4198 
4199  /* initializes right hand side of lifted valid inequality */
4200  *liftrhs = alpha0;
4201 
4202  /* sequentially up-lifts all variables in GFC1 GUBs */
4203  for( j = 0; j < ngubconsGFC1; j++ )
4204  {
4205  liftgubconsidx = gubconsGFC1[j];
4206  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4207 
4208  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4209  * compute minweight table via updated unfinished table and aleady upto date finished table;
4210  */
4211  k = 0;
4212  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4213  {
4214  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4215  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4216  assert(ngubconsGNC1 > 0);
4217 
4218  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4219  * are considered for the lifting, i.e., not capacity exceeding
4220  */
4221  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4222  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4223  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4224  assert(k >= 1);
4225 
4226  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4227  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4228  */
4229  weight = weights[liftgubvars[0]];
4230 
4231  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4232  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4233  for( w = ngubconsGNC1-1; w >= 1; w-- )
4234  {
4235  weightdiff1 = weightdiff2;
4236  weightdiff2 = unfinished[w] - weight;
4237 
4238  if( unfinished[w] < weightdiff1 )
4239  unfinished[w] = weightdiff1;
4240  else
4241  break;
4242  }
4243  ngubconsGNC1--;
4244 
4245  /* computes minweights table by combining unfished and fished tables */
4246  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4247  assert(minweights[0] == 0);
4248  }
4249  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4250  * are therefore not in the unfinished table
4251  */
4252  else
4253  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4254 
4255 #ifndef NDEBUG
4256  nliftgubC1 = k;
4257 #endif
4258  nliftgubvars = k;
4259  sumliftcoef = 0;
4260 
4261  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4262  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4263  {
4264  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4265  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4266  {
4267  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4268  weight = weights[liftvar];
4269  assert(weight > 0);
4270  assert(liftvar >= 0 && liftvar < nvars);
4271  assert(capacity - weight >= 0);
4272 
4273  /* put variable into array of variables in GUB that are considered for the lifting,
4274  * i.e., not capacity exceeding
4275  */
4276  liftgubvars[nliftgubvars] = liftvar;
4277  nliftgubvars++;
4278 
4279  /* knapsack problem is infeasible:
4280  * sets z = 0
4281  */
4282  if( capacity - fixedonesweight - weight < 0 )
4283  {
4284  z = 0;
4285  }
4286  /* knapsack problem is feasible:
4287  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4288  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4289  */
4290  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4291  {
4292  z = *liftrhs;
4293  }
4294  /* knapsack problem is feasible:
4295  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4296  */
4297  else
4298  {
4299  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4300  left = 0;
4301  right = (*liftrhs) + 1;
4302  while( left < right - 1 )
4303  {
4304  middle = (left + right) / 2;
4305  assert(0 <= middle && middle < minweightslen);
4306  if( minweights[middle] <= capacity - fixedonesweight - weight )
4307  left = middle;
4308  else
4309  right = middle;
4310  }
4311  assert(left == right - 1);
4312  assert(0 <= left && left < minweightslen);
4313  assert(minweights[left] <= capacity - fixedonesweight - weight);
4314  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4315 
4316  /* now z = left */
4317  z = left;
4318  assert(z <= *liftrhs);
4319  }
4320 
4321  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4322  liftcoef = (*liftrhs) - z;
4323  liftcoefs[liftvar] = liftcoef;
4324  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4325 
4326  /* updates activity of current valid inequality */
4327  (*cutact) += liftcoef * solvals[liftvar];
4328 
4329  /* updates sum of all lifting coefficients in GUB */
4330  sumliftcoef += liftcoefs[liftvar];
4331  }
4332  else
4333  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4334  }
4335  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4336  assert(nliftgubvars > nliftgubC1);
4337 
4338  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4339  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4340  * not needed for GF GUBs
4341  */
4342  if( sumliftcoef == 0 )
4343  {
4344  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4345  {
4346  weight = weights[liftgubvars[0]];
4347  /* update finished table and minweights table by applying special case of
4348  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4349  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4350  */
4351  for( w = minweightslen-1; w >= 1; w-- )
4352  {
4353  SCIP_Longint tmpval;
4354 
4355  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4356  finished[w] = MIN(finished[w], tmpval);
4357 
4358  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4359  minweights[w] = MIN(minweights[w], tmpval);
4360  }
4361  }
4362  else
4363  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4364 
4365  continue;
4366  }
4367 
4368  /* enlarges current minweights tables(finished, unfinished, minweights):
4369  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4370  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4371  * and sets minweights_i[w] = infinity for
4372  * 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
4373  */
4374  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4375  tmpsize = minweightssize;
4376  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4377  tmplen = minweightslen;
4378  tmpsize = minweightssize;
4379  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4380  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4381 
4382  /* update finished table and minweight table;
4383  * note that instead of computing minweight table from updated finished and updated unfinished table again
4384  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4385  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4386  * not needed because only finished table changed at this point and the change was "adding" one weight)
4387  *
4388  * update formular for minweight table is: minweight_i+1[w] =
4389  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4390  * formular for finished table has the same pattern.
4391  */
4392  for( w = minweightslen-1; w >= 0; w-- )
4393  {
4394  SCIP_Longint minminweight;
4395  SCIP_Longint minfinished;
4396 
4397  for( k = 0; k < nliftgubvars; k++ )
4398  {
4399  liftcoef = liftcoefs[liftgubvars[k]];
4400  weight = weights[liftgubvars[k]];
4401 
4402  if( w < liftcoef )
4403  {
4404  minfinished = MIN(finished[w], weight);
4405  minminweight = MIN(minweights[w], weight);
4406 
4407  finished[w] = minfinished;
4408  minweights[w] = minminweight;
4409  }
4410  else
4411  {
4412  SCIP_Longint tmpval;
4413 
4414  assert(w >= liftcoef);
4415 
4416  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4417  minfinished = MIN(finished[w], tmpval);
4418 
4419  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4420  minminweight = MIN(minweights[w], tmpval);
4421 
4422  finished[w] = minfinished;
4423  minweights[w] = minminweight;
4424  }
4425  }
4426  }
4427  assert(minweights[0] == 0);
4428  }
4429  assert(ngubconsGNC1 == 0);
4430 
4431  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4432  * therefore, only work with minweight table from here on
4433  */
4434 
4435  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4436  for( j = 0; j < ngubconsGC2; j++ )
4437  {
4438  liftgubconsidx = gubconsGC2[j];
4439 
4440  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4441  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4442  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4443  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4444 
4445  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4446  weight = weights[liftvar];
4447 
4448  assert(liftvar >= 0 && liftvar < nvars);
4449  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4450  assert(weight > 0);
4451 
4452  /* uses binary search to find
4453  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4454  */
4455  left = 0;
4456  right = minweightslen;
4457  while( left < right - 1 )
4458  {
4459  middle = (left + right) / 2;
4460  assert(0 <= middle && middle < minweightslen);
4461  if( minweights[middle] <= capacity - fixedonesweight + weight )
4462  left = middle;
4463  else
4464  right = middle;
4465  }
4466  assert(left == right - 1);
4467  assert(0 <= left && left < minweightslen);
4468  assert(minweights[left] <= capacity - fixedonesweight + weight);
4469  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4470 
4471  /* now z = left */
4472  z = left;
4473  assert(z >= *liftrhs);
4474 
4475  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4476  liftcoef = z - (*liftrhs);
4477  liftcoefs[liftvar] = liftcoef;
4478  assert(liftcoef >= 0);
4479 
4480  /* updates sum of weights of variables fixed to one */
4481  fixedonesweight -= weight;
4482 
4483  /* updates right-hand side of current valid inequality */
4484  (*liftrhs) += liftcoef;
4485  assert(*liftrhs >= alpha0);
4486 
4487  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4488  if( liftcoef == 0 )
4489  continue;
4490 
4491  /* updates activity of current valid inequality */
4492  (*cutact) += liftcoef * solvals[liftvar];
4493 
4494  /* enlarges current minweight table:
4495  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4496  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4497  * and sets minweights_i[w] = infinity for
4498  * 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
4499  */
4500  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4501 
4502  /* updates minweight table: minweight_i+1[w] =
4503  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4504  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4505  */
4506  for( w = minweightslen - 1; w >= 0; w-- )
4507  {
4508  if( w < liftcoef )
4509  {
4510  min = MIN(minweights[w], weight);
4511  minweights[w] = min;
4512  }
4513  else
4514  {
4515  SCIP_Longint tmpval;
4516 
4517  assert(w >= liftcoef);
4518 
4519  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4520  min = MIN(minweights[w], tmpval);
4521  minweights[w] = min;
4522  }
4523  }
4524  }
4525  assert(fixedonesweight == 0);
4526  assert(*liftrhs >= alpha0);
4527 
4528  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4529  for( j = 0; j < ngubconsGR; j++ )
4530  {
4531  liftgubconsidx = gubconsGR[j];
4532 
4533  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4534  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4535 
4536  sumliftcoef = 0;
4537  nliftgubvars = 0;
4538  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4539  {
4540  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4541  {
4542  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4543  weight = weights[liftvar];
4544  assert(weight > 0);
4545  assert(liftvar >= 0 && liftvar < nvars);
4546  assert(capacity - weight >= 0);
4547  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4548 
4549  /* put variable into array of variables in GUB that are considered for the lifting,
4550  * i.e., not capacity exceeding
4551  */
4552  liftgubvars[nliftgubvars] = liftvar;
4553  nliftgubvars++;
4554 
4555  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4556  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4557  */
4558  if( minweights[*liftrhs] <= capacity - weight )
4559  {
4560  z = *liftrhs;
4561  }
4562  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4563  */
4564  else
4565  {
4566  left = 0;
4567  right = (*liftrhs) + 1;
4568  while( left < right - 1 )
4569  {
4570  middle = (left + right) / 2;
4571  assert(0 <= middle && middle < minweightslen);
4572  if( minweights[middle] <= capacity - weight )
4573  left = middle;
4574  else
4575  right = middle;
4576  }
4577  assert(left == right - 1);
4578  assert(0 <= left && left < minweightslen);
4579  assert(minweights[left] <= capacity - weight);
4580  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4581 
4582  /* now z = left */
4583  z = left;
4584  assert(z <= *liftrhs);
4585  }
4586  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4587  liftcoef = (*liftrhs) - z;
4588  liftcoefs[liftvar] = liftcoef;
4589  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4590 
4591  /* updates activity of current valid inequality */
4592  (*cutact) += liftcoef * solvals[liftvar];
4593 
4594  /* updates sum of all lifting coefficients in GUB */
4595  sumliftcoef += liftcoefs[liftvar];
4596  }
4597  else
4598  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4599  }
4600  assert(nliftgubvars >= 1); /* at least one variable is in R */
4601 
4602  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4603  if( sumliftcoef == 0 )
4604  continue;
4605 
4606  /* updates minweight table: minweight_i+1[w] =
4607  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4608  */
4609  for( w = *liftrhs; w >= 0; w-- )
4610  {
4611  for( k = 0; k < nliftgubvars; k++ )
4612  {
4613  liftcoef = liftcoefs[liftgubvars[k]];
4614  weight = weights[liftgubvars[k]];
4615 
4616  if( w < liftcoef )
4617  {
4618  min = MIN(minweights[w], weight);
4619  minweights[w] = min;
4620  }
4621  else
4622  {
4623  SCIP_Longint tmpval;
4624 
4625  assert(w >= liftcoef);
4626 
4627  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4628  min = MIN(minweights[w], tmpval);
4629  minweights[w] = min;
4630  }
4631  }
4632  }
4633  assert(minweights[0] == 0);
4634  }
4635 
4636  /* frees temporary memory */
4637  SCIPfreeBufferArray(scip, &minweights);
4638  SCIPfreeBufferArray(scip, &finished);
4639  SCIPfreeBufferArray(scip, &unfinished);
4640  SCIPfreeBufferArray(scip, &liftgubvars);
4641  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4642  SCIPfreeBufferArray(scip, &gubconsGNC1);
4643 
4644  return SCIP_OKAY;
4645 }
4646 
4647 /** lifts given minimal cover inequality
4648  * \f[
4649  * \sum_{j \in C} x_j \leq |C| - 1
4650  * \f]
4651  * valid for
4652  * \f[
4653  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4654  * \f]
4655  * to a valid inequality
4656  * \f[
4657  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4658  * \f]
4659  * for
4660  * \f[
4661  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4662  * \f]
4663  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4664  */
4665 static
4667  SCIP* scip, /**< SCIP data structure */
4668  SCIP_VAR** vars, /**< variables in knapsack constraint */
4669  int nvars, /**< number of variables in knapsack constraint */
4670  int ntightened, /**< number of variables with tightened upper bound */
4671  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4672  SCIP_Longint capacity, /**< capacity of knapsack */
4673  SCIP_Real* solvals, /**< solution values of all problem variables */
4674  int* covervars, /**< cover variables */
4675  int* noncovervars, /**< noncover variables */
4676  int ncovervars, /**< number of cover variables */
4677  int nnoncovervars, /**< number of noncover variables */
4678  SCIP_Longint coverweight, /**< weight of cover */
4679  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4680  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4681  )
4682 {
4683  SCIP_Longint* maxweightsums;
4684  SCIP_Longint* intervalends;
4685  SCIP_Longint* rhos;
4686  SCIP_Real* sortkeys;
4687  SCIP_Longint lambda;
4688  int j;
4689  int h;
4690 
4691  assert(scip != NULL);
4692  assert(vars != NULL);
4693  assert(nvars >= 0);
4694  assert(weights != NULL);
4695  assert(capacity >= 0);
4696  assert(solvals != NULL);
4697  assert(covervars != NULL);
4698  assert(noncovervars != NULL);
4699  assert(ncovervars > 0 && ncovervars <= nvars);
4700  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4701  assert(ncovervars + nnoncovervars == nvars - ntightened);
4702  assert(liftcoefs != NULL);
4703  assert(cutact != NULL);
4704 
4705  /* allocates temporary memory */
4706  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4707  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4708  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4709  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4710 
4711  /* initializes data structures */
4712  BMSclearMemoryArray(liftcoefs, nvars);
4713  *cutact = 0.0;
4714 
4715  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4716  * and calculates activity of current valid inequality
4717  */
4718  for( j = 0; j < ncovervars; j++ )
4719  {
4720  assert(liftcoefs[covervars[j]] == 0.0);
4721  liftcoefs[covervars[j]] = 1.0;
4722  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4723  (*cutact) += solvals[covervars[j]];
4724  }
4725  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4726 
4727  /* calculates weight excess of cover C */
4728  lambda = coverweight - capacity;
4729  assert(lambda > 0);
4730 
4731  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4732  maxweightsums[0] = 0;
4733  for( h = 1; h <= ncovervars; h++ )
4734  {
4735  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4736  intervalends[h-1] = maxweightsums[h] - lambda;
4737  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4738  }
4739 
4740  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4741  for( j = 0; j < nnoncovervars; j++ )
4742  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4743  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4744 
4745  /* calculates lifting coefficient for all variables in N\C */
4746  h = 0;
4747  for( j = 0; j < nnoncovervars; j++ )
4748  {
4749  int liftvar;
4750  SCIP_Longint weight;
4751  SCIP_Real liftcoef;
4752 
4753  liftvar = noncovervars[j];
4754  weight = weights[liftvar];
4755 
4756  while( intervalends[h] < weight )
4757  h++;
4758 
4759  if( h == 0 )
4760  liftcoef = h;
4761  else
4762  {
4763  if( weight <= intervalends[h-1] + rhos[h] )
4764  {
4765  SCIP_Real tmp1;
4766  SCIP_Real tmp2;
4767  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4768  tmp2 = (SCIP_Real) rhos[1];
4769  liftcoef = h - ( tmp1 / tmp2 );
4770  }
4771  else
4772  liftcoef = h;
4773  }
4774 
4775  /* sets lifting coefficient */
4776  assert(liftcoefs[liftvar] == 0.0);
4777  liftcoefs[liftvar] = liftcoef;
4778 
4779  /* updates activity of current valid inequality */
4780  (*cutact) += liftcoef * solvals[liftvar];
4781  }
4782 
4783  /* frees temporary memory */
4784  SCIPfreeBufferArray(scip, &rhos);
4785  SCIPfreeBufferArray(scip, &intervalends);
4786  SCIPfreeBufferArray(scip, &maxweightsums);
4787  SCIPfreeBufferArray(scip, &sortkeys);
4788 
4789  return SCIP_OKAY;
4790 }
4791 
4792 
4793 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4794  * given knapsack problem
4795 */
4796 static
4798  SCIP* scip, /**< SCIP data structure */
4799  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4800  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4801  SCIP_VAR** vars, /**< variables in knapsack constraint */
4802  int nvars, /**< number of variables in knapsack constraint */
4803  int ntightened, /**< number of variables with tightened upper bound */
4804  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4805  SCIP_Longint capacity, /**< capacity of knapsack */
4806  SCIP_Real* solvals, /**< solution values of all problem variables */
4807  int* mincovervars, /**< mincover variables */
4808  int* nonmincovervars, /**< nonmincover variables */
4809  int nmincovervars, /**< number of mincover variables */
4810  int nnonmincovervars, /**< number of nonmincover variables */
4811  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4812  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4813  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4814  int* ncuts /**< pointer to add up the number of found cuts */
4815  )
4816 {
4817  int* varsC1;
4818  int* varsC2;
4819  int* varsF;
4820  int* varsR;
4821  int nvarsC1;
4822  int nvarsC2;
4823  int nvarsF;
4824  int nvarsR;
4825  SCIP_Real cutact;
4826  int* liftcoefs;
4827  int liftrhs;
4828 
4829  assert( cutoff != NULL );
4830  *cutoff = FALSE;
4831 
4832  /* allocates temporary memory */
4833  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4834  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4835  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4836  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4837  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4838 
4839  /* 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
4840  * as follows
4841  * C_2 = { j in C : x*_j = 1 } and
4842  * C_1 = C\C_2
4843  */
4844  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4845  assert(nvarsC1 + nvarsC2 == nmincovervars);
4846  assert(nmincovervars > 0);
4847  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4848 
4849  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4850  if( nvarsC1 < 2 && nvarsC2 > 0)
4851  {
4852  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4853  assert(nvarsC1 >= 1);
4854  }
4855  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4856 
4857  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4858  * R = { j in N\C : x*_j = 0 } and
4859  * F = (N\C)\F
4860  */
4861  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4862  assert(nvarsF + nvarsR == nnonmincovervars);
4863  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4864 
4865  /* lift cuts without GUB information */
4866  if( gubset == NULL )
4867  {
4868  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4869  * lifting procedure
4870  */
4871  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4872 
4873  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4874  *
4875  * 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 }
4876  *
4877  * 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
4878  *
4879  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4880  *
4881  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4882  * up-lifting for the variables in R according to the second level lifting sequence
4883  */
4884  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4885  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4886  }
4887  /* lift cuts with GUB information */
4888  else
4889  {
4890  int* gubconsGC1;
4891  int* gubconsGC2;
4892  int* gubconsGFC1;
4893  int* gubconsGR;
4894  int ngubconsGC1;
4895  int ngubconsGC2;
4896  int ngubconsGFC1;
4897  int ngubconsGR;
4898  int ngubconss;
4899  int nconstightened;
4900  int maxgubvarssize;
4901 
4902  assert(nvars == gubset->nvars);
4903 
4904  ngubconsGC1 = 0;
4905  ngubconsGC2 = 0;
4906  ngubconsGFC1 = 0;
4907  ngubconsGR = 0;
4908  ngubconss = gubset->ngubconss;
4909  nconstightened = 0;
4910  maxgubvarssize = 0;
4911 
4912  /* allocates temporary memory */
4913  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4914  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4915  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4916  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4917 
4918  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4919  * the GUBs for the sequential GUB wise lifting procedure
4920  */
4921  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4922  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4923  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4924 
4925  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4926  *
4927  * 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,
4928  * sum_{j in Q_i} x_j <= 1, forall i in I }
4929  *
4930  * 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
4931  *
4932  * 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 },
4933  *
4934  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4935  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4936  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4937  */
4938  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4939  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4940  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4941 
4942  /* frees temporary memory */
4943  SCIPfreeBufferArray(scip, &gubconsGR);
4944  SCIPfreeBufferArray(scip, &gubconsGFC1);
4945  SCIPfreeBufferArray(scip, &gubconsGC2);
4946  SCIPfreeBufferArray(scip, &gubconsGC1);
4947  }
4948 
4949  /* checks, if lifting yielded a violated cut */
4950  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4951  {
4952  SCIP_ROW* row;
4953  char name[SCIP_MAXSTRLEN];
4954  int j;
4955 
4956  /* creates LP row */
4957  assert( cons == NULL || sepa == NULL );
4958  if ( cons != NULL )
4959  {
4961  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4962  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4963  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4964  }
4965  else if ( sepa != NULL )
4966  {
4967  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4968  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4969  }
4970  else
4971  {
4972  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4973  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4974  }
4975 
4976  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4977  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4978  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4979  for( j = 0; j < nvarsC1; j++ )
4980  {
4981  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4982  }
4983  for( j = 0; j < nvarsC2; j++ )
4984  {
4985  if( liftcoefs[varsC2[j]] > 0 )
4986  {
4987  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4988  }
4989  }
4990  for( j = 0; j < nvarsF; j++ )
4991  {
4992  if( liftcoefs[varsF[j]] > 0 )
4993  {
4994  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4995  }
4996  }
4997  for( j = 0; j < nvarsR; j++ )
4998  {
4999  if( liftcoefs[varsR[j]] > 0 )
5000  {
5001  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5002  }
5003  }
5004  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5005 
5006  /* checks, if cut is violated enough */
5007  if( SCIPisCutEfficacious(scip, sol, row) )
5008  {
5009  if( cons != NULL )
5010  {
5011  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5012  }
5013  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5014  (*ncuts)++;
5015  }
5016  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5017  }
5018 
5019  /* frees temporary memory */
5020  SCIPfreeBufferArray(scip, &liftcoefs);
5021  SCIPfreeBufferArray(scip, &varsR);
5022  SCIPfreeBufferArray(scip, &varsF);
5023  SCIPfreeBufferArray(scip, &varsC2);
5024  SCIPfreeBufferArray(scip, &varsC1);
5025 
5026  return SCIP_OKAY;
5027 }
5028 
5029 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5030 static
5032  SCIP* scip, /**< SCIP data structure */
5033  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5034  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5035  SCIP_VAR** vars, /**< variables in knapsack constraint */
5036  int nvars, /**< number of variables in knapsack constraint */
5037  int ntightened, /**< number of variables with tightened upper bound */
5038  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5039  SCIP_Longint capacity, /**< capacity of knapsack */
5040  SCIP_Real* solvals, /**< solution values of all problem variables */
5041  int* feassetvars, /**< variables in feasible set */
5042  int* nonfeassetvars, /**< variables not in feasible set */
5043  int nfeassetvars, /**< number of variables in feasible set */
5044  int nnonfeassetvars, /**< number of variables not in feasible set */
5045  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5046  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5047  int* ncuts /**< pointer to add up the number of found cuts */
5048  )
5049 {
5050  int* varsT1;
5051  int* varsT2;
5052  int* varsF;
5053  int* varsR;
5054  int* liftcoefs;
5055  SCIP_Real cutact;
5056  int nvarsT1;
5057  int nvarsT2;
5058  int nvarsF;
5059  int nvarsR;
5060  int liftrhs;
5061  int j;
5062 
5063  assert( cutoff != NULL );
5064  *cutoff = FALSE;
5065 
5066  /* allocates temporary memory */
5067  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5068  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5069  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5070  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5071  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5072 
5073  /* 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
5074  * as follows
5075  * T_2 = { j in T : x*_j = 1 } and
5076  * T_1 = T\T_2
5077  */
5078  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5079  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5080 
5081  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5082  if( nvarsT1 == 0 && nvarsT2 > 0)
5083  {
5084  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5085  assert(nvarsT1 == 1);
5086  }
5087  assert(nvarsT2 == 0 || nvarsT1 > 0);
5088 
5089  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5090  * R = { j in N\T : x*_j = 0 } and
5091  * F = (N\T)\F
5092  */
5093  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5094  assert(nvarsF + nvarsR == nnonfeassetvars);
5095  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5096 
5097  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5098  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5099  * is included in the sorting routine)
5100  */
5101  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5102 
5103  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5104  *
5105  * 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 }
5106  *
5107  * 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
5108  *
5109  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5110  *
5111  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5112  * up-lifting for the variabels in R according to the second level lifting sequence
5113  */
5114  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5115  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5116 
5117  /* checks, if lifting yielded a violated cut */
5118  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5119  {
5120  SCIP_ROW* row;
5121  char name[SCIP_MAXSTRLEN];
5122 
5123  /* creates LP row */
5124  assert( cons == NULL || sepa == NULL );
5125  if( cons != NULL )
5126  {
5128  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5129  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5130  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5131  }
5132  else if ( sepa != NULL )
5133  {
5134  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5135  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5136  }
5137  else
5138  {
5139  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5140  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5141  }
5142 
5143  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5144  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5145  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5146  for( j = 0; j < nvarsT1; j++ )
5147  {
5148  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5149  }
5150  for( j = 0; j < nvarsT2; j++ )
5151  {
5152  if( liftcoefs[varsT2[j]] > 0 )
5153  {
5154  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5155  }
5156  }
5157  for( j = 0; j < nvarsF; j++ )
5158  {
5159  if( liftcoefs[varsF[j]] > 0 )
5160  {
5161  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5162  }
5163  }
5164  for( j = 0; j < nvarsR; j++ )
5165  {
5166  if( liftcoefs[varsR[j]] > 0 )
5167  {
5168  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5169  }
5170  }
5171  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5172 
5173  /* checks, if cut is violated enough */
5174  if( SCIPisCutEfficacious(scip, sol, row) )
5175  {
5176  if( cons != NULL )
5177  {
5178  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5179  }
5180  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5181  (*ncuts)++;
5182  }
5183  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5184  }
5185 
5186  /* frees temporary memory */
5187  SCIPfreeBufferArray(scip, &liftcoefs);
5188  SCIPfreeBufferArray(scip, &varsR);
5189  SCIPfreeBufferArray(scip, &varsF);
5190  SCIPfreeBufferArray(scip, &varsT2);
5191  SCIPfreeBufferArray(scip, &varsT1);
5192 
5193  return SCIP_OKAY;
5194 }
5195 
5196 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5197 static
5199  SCIP* scip, /**< SCIP data structure */
5200  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5201  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5202  SCIP_VAR** vars, /**< variables in knapsack constraint */
5203  int nvars, /**< number of variables in knapsack constraint */
5204  int ntightened, /**< number of variables with tightened upper bound */
5205  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5206  SCIP_Longint capacity, /**< capacity of knapsack */
5207  SCIP_Real* solvals, /**< solution values of all problem variables */
5208  int* mincovervars, /**< mincover variables */
5209  int* nonmincovervars, /**< nonmincover variables */
5210  int nmincovervars, /**< number of mincover variables */
5211  int nnonmincovervars, /**< number of nonmincover variables */
5212  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5213  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5214  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5215  int* ncuts /**< pointer to add up the number of found cuts */
5216  )
5217 {
5218  SCIP_Real* realliftcoefs;
5219  SCIP_Real cutact;
5220  int liftrhs;
5221 
5222  assert( cutoff != NULL );
5223  *cutoff = FALSE;
5224  cutact = 0.0;
5225 
5226  /* allocates temporary memory */
5227  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5228 
5229  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5230  *
5231  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5232  *
5233  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5234  *
5235  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5236  *
5237  * uses superadditive up-lifting for the variables in N\C.
5238  */
5239  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5240  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5241  liftrhs = nmincovervars - 1;
5242 
5243  /* checks, if lifting yielded a violated cut */
5244  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5245  {
5246  SCIP_ROW* row;
5247  char name[SCIP_MAXSTRLEN];
5248  int j;
5249 
5250  /* creates LP row */
5251  assert( cons == NULL || sepa == NULL );
5252  if ( cons != NULL )
5253  {
5255  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5256  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5257  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5258  }
5259  else if ( sepa != NULL )
5260  {
5261  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5262  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5263  }
5264  else
5265  {
5266  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5267  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5268  }
5269 
5270  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5271  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5272  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5273  for( j = 0; j < nmincovervars; j++ )
5274  {
5275  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5276  }
5277  for( j = 0; j < nnonmincovervars; j++ )
5278  {
5279  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5280  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5281  {
5282  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5283  }
5284  }
5285  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5286 
5287  /* checks, if cut is violated enough */
5288  if( SCIPisCutEfficacious(scip, sol, row) )
5289  {
5290  if( cons != NULL )
5291  {
5292  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5293  }
5294  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5295  (*ncuts)++;
5296  }
5297  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5298  }
5299 
5300  /* frees temporary memory */
5301  SCIPfreeBufferArray(scip, &realliftcoefs);
5302 
5303  return SCIP_OKAY;
5304 }
5305 
5306 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5307  * 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
5308  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5309  * note that all variables with x*_j = 1 will be removed last
5310  */
5311 static
5313  SCIP* scip, /**< SCIP data structure */
5314  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5315  SCIP_Longint capacity, /**< capacity of knapsack */
5316  SCIP_Real* solvals, /**< solution values of all problem variables */
5317  int* covervars, /**< pointer to store cover variables */
5318  int* noncovervars, /**< pointer to store noncover variables */
5319  int* ncovervars, /**< pointer to store number of cover variables */
5320  int* nnoncovervars, /**< pointer to store number of noncover variables */
5321  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5322  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5323  )
5324 {
5325  SORTKEYPAIR** sortkeypairs;
5326  SORTKEYPAIR** sortkeypairssorted;
5327  SCIP_Longint minweight;
5328  int nsortkeypairs;
5329  int minweightidx;
5330  int j;
5331  int k;
5332 
5333  assert(scip != NULL);
5334  assert(covervars != NULL);
5335  assert(noncovervars != NULL);
5336  assert(ncovervars != NULL);
5337  assert(*ncovervars > 0);
5338  assert(nnoncovervars != NULL);
5339  assert(*nnoncovervars >= 0);
5340  assert(coverweight != NULL);
5341  assert(*coverweight > 0);
5342  assert(*coverweight > capacity);
5343 
5344  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5345  * order */
5346  nsortkeypairs = *ncovervars;
5347  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5348  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5349 
5350  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5351  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5352  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5353  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5354  */
5355  assert(*ncovervars == nsortkeypairs);
5356  if( modtransused )
5357  {
5358  for( j = 0; j < *ncovervars; j++ )
5359  {
5360  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5361  sortkeypairssorted[j] = sortkeypairs[j];
5362 
5363  sortkeypairs[j]->key1 = solvals[covervars[j]];
5364  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5365  }
5366  }
5367  else
5368  {
5369  for( j = 0; j < *ncovervars; j++ )
5370  {
5371  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5372  sortkeypairssorted[j] = sortkeypairs[j];
5373 
5374  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5375  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5376  }
5377  }
5378  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5379 
5380  /* gets j' with a_j' = min{ a_j : j in C } */
5381  minweightidx = 0;
5382  minweight = weights[covervars[minweightidx]];
5383  for( j = 1; j < *ncovervars; j++ )
5384  {
5385  if( weights[covervars[j]] <= minweight )
5386  {
5387  minweightidx = j;
5388  minweight = weights[covervars[minweightidx]];
5389  }
5390  }
5391  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5392  assert(minweight > 0 && minweight <= *coverweight);
5393 
5394  j = 0;
5395  /* removes variables from C until the remaining variables form a minimal cover */
5396  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5397  {
5398  assert(minweightidx >= j);
5399  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5400 
5401  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5402  if( (*coverweight) - weights[covervars[j]] <= capacity )
5403  {
5404  ++j;
5405  continue;
5406  }
5407 
5408  /* adds j to N\C */
5409  noncovervars[*nnoncovervars] = covervars[j];
5410  (*nnoncovervars)++;
5411 
5412  /* removes j from C */
5413  (*coverweight) -= weights[covervars[j]];
5414  for( k = j; k < (*ncovervars) - 1; k++ )
5415  covervars[k] = covervars[k+1];
5416  (*ncovervars)--;
5417 
5418  /* updates j' with a_j' = min{ a_j : j in C } */
5419  if( j == minweightidx )
5420  {
5421  minweightidx = 0;
5422  minweight = weights[covervars[minweightidx]];
5423  for( k = 1; k < *ncovervars; k++ )
5424  {
5425  if( weights[covervars[k]] <= minweight )
5426  {
5427  minweightidx = k;
5428  minweight = weights[covervars[minweightidx]];
5429  }
5430  }
5431  assert(minweight > 0 && minweight <= *coverweight);
5432  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5433  }
5434  else
5435  {
5436  assert(minweightidx > j);
5437  minweightidx--;
5438  }
5439  /* j needs to stay the same */
5440  }
5441  assert((*coverweight) > capacity);
5442  assert((*coverweight) - minweight <= capacity);
5443 
5444  /* frees temporary memory */
5445  for( j = nsortkeypairs-1; j >= 0; j-- )
5446  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5447  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5448  SCIPfreeBufferArray(scip, &sortkeypairs);
5449 
5450  return SCIP_OKAY;
5451 }
5452 
5453 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5454  * they were chosen to be in C_init:
5455  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5456  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5457  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5458  * and all subsequent feasible sets.
5459  */
5460 static
5462  SCIP* scip, /**< SCIP data structure */
5463  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5464  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5465  SCIP_VAR** vars, /**< variables in knapsack constraint */
5466  int nvars, /**< number of variables in knapsack constraint */
5467  int ntightened, /**< number of variables with tightened upper bound */
5468  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5469  SCIP_Longint capacity, /**< capacity of knapsack */
5470  SCIP_Real* solvals, /**< solution values of all problem variables */
5471  int* covervars, /**< pointer to store cover variables */
5472  int* noncovervars, /**< pointer to store noncover variables */
5473  int* ncovervars, /**< pointer to store number of cover variables */
5474  int* nnoncovervars, /**< pointer to store number of noncover variables */
5475  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5476  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5477  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5478  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5479  int* ncuts /**< pointer to add up the number of found cuts */
5480  )
5481 {
5482  SCIP_Real* sortkeys;
5483  int j;
5484  int k;
5485 
5486  assert(scip != NULL);
5487  assert(covervars != NULL);
5488  assert(noncovervars != NULL);
5489  assert(ncovervars != NULL);
5490  assert(*ncovervars > 0);
5491  assert(nnoncovervars != NULL);
5492  assert(*nnoncovervars >= 0);
5493  assert(coverweight != NULL);
5494  assert(*coverweight > 0);
5495  assert(*coverweight > capacity);
5496  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5497  assert(cutoff != NULL);
5498 
5499  *cutoff = FALSE;
5500 
5501  /* allocates temporary memory */
5502  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5503 
5504  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5505  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5506  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5507  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5508  */
5509  if( modtransused )
5510  {
5511  for( j = 0; j < *ncovervars; j++ )
5512  {
5513  sortkeys[j] = solvals[covervars[j]];
5514  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5515  }
5516  }
5517  else
5518  {
5519  for( j = 0; j < *ncovervars; j++ )
5520  {
5521  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5522  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5523  }
5524  }
5525  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5526 
5527  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5528  * in addition to an extended weight inequality this gives cardinality inequalities */
5529  while( *ncovervars >= 2 )
5530  {
5531  /* adds first element of C_init to N\C_init */
5532  noncovervars[*nnoncovervars] = covervars[0];
5533  (*nnoncovervars)++;
5534 
5535  /* removes first element from C_init */
5536  (*coverweight) -= weights[covervars[0]];
5537  for( k = 0; k < (*ncovervars) - 1; k++ )
5538  covervars[k] = covervars[k+1];
5539  (*ncovervars)--;
5540 
5541  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5542  if( (*coverweight) <= capacity )
5543  {
5544  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5545  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5546  }
5547 
5548  /* stop if cover is too large */
5549  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5550  break;
5551  }
5552 
5553  /* frees temporary memory */
5554  SCIPfreeBufferArray(scip, &sortkeys);
5555 
5556  return SCIP_OKAY;
5557 }
5558 
5559 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5561  SCIP* scip, /**< SCIP data structure */
5562  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5563  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5564  SCIP_VAR** vars, /**< variables in knapsack constraint */
5565  int nvars, /**< number of variables in knapsack constraint */
5566  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5567  SCIP_Longint capacity, /**< capacity of knapsack */
5568  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5569  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5570  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5571  int* ncuts /**< pointer to add up the number of found cuts */
5572  )
5573 {
5574  SCIP_Real* solvals;
5575  int* covervars;
5576  int* noncovervars;
5577  SCIP_Bool coverfound;
5578  SCIP_Bool fractional;
5579  SCIP_Bool modtransused;
5580  SCIP_Longint coverweight;
5581  int ncovervars;
5582  int nnoncovervars;
5583  int ntightened;
5584 
5585  assert(scip != NULL);
5586  assert(capacity >= 0);
5587  assert(cutoff != NULL);
5588  assert(ncuts != NULL);
5589 
5590  *cutoff = FALSE;
5591 
5592  if( nvars == 0 )
5593  return SCIP_OKAY;
5594 
5595  assert(vars != NULL);
5596  assert(nvars > 0);
5597  assert(weights != NULL);
5598 
5599  /* increase age of constraint (age is reset to zero, if a cut was found) */
5600  if( cons != NULL )
5601  {
5602  SCIP_CALL( SCIPincConsAge(scip, cons) );
5603  }
5604 
5605  /* allocates temporary memory */
5606  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5607  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5608  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5609 
5610  /* gets solution values of all problem variables */
5611  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5612 
5613 #ifdef SCIP_DEBUG
5614  {
5615  int i;
5616 
5617  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5618  cons == NULL ? "-" : SCIPconsGetName(cons));
5619  for( i = 0; i < nvars; ++i )
5620  {
5621  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5622  }
5623  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5624  }
5625 #endif
5626 
5627  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5628  */
5629  if( usegubs )
5630  {
5631  SCIP_GUBSET* gubset;
5632 
5633  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5634 
5635  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5636  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5637 
5638  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5639  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5640  assert(gubset->ngubconss <= nvars);
5641 
5642  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5643  * MODIFIED transformed separation problem and taking into account the following fixing:
5644  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5645  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5646  * if one exists
5647  */
5648  modtransused = TRUE;
5649  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5650  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5651 
5652  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5653 
5654  /* if x* is not fractional we stop the separation routine */
5655  if( !fractional )
5656  {
5657  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5658 
5659  /* frees memory for GUB set data structure */
5660  GUBsetFree(scip, &gubset);
5661 
5662  goto TERMINATE;
5663  }
5664 
5665  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5666  if( coverfound )
5667  {
5668  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5669  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5670  */
5671  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5672  &nnoncovervars, &coverweight, modtransused) );
5673 
5674  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5675  if( gubset->ngubconss < nvars )
5676  {
5677  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5678  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5679  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5680  }
5681  else
5682  {
5683  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5684  * GUB information
5685  */
5686  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5687  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5688  }
5689  }
5690 
5691  /* frees memory for GUB set data structure */
5692  GUBsetFree(scip, &gubset);
5693  }
5694  else
5695  {
5696  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5697  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5698  */
5699 
5700  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5701  * MODIFIED transformed separation problem and taking into account the following fixing:
5702  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5703  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5704  * if one exists
5705  */
5706  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5707  modtransused = TRUE;
5708  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5709  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5710  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5711 
5712  /* if x* is not fractional we stop the separation routine */
5713  if( !fractional )
5714  goto TERMINATE;
5715 
5716  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5717  if( coverfound )
5718  {
5719  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5720  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5721  */
5722  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5723  &nnoncovervars, &coverweight, modtransused) );
5724 
5725  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5726  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5727  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5728 
5729  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5730  {
5731  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5732  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5733  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5734  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5735  }
5736  }
5737  }
5738 
5739  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5740  if ( ! (*cutoff) )
5741  {
5742  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5743  * transformed separation problem and taking into account the following fixing:
5744  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5745  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5746  * if one exists
5747  */
5748  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5749  modtransused = FALSE;
5750  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5751  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5752  assert(fractional);
5753  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5754 
5755  /* if no cover was found we stop the separation routine */
5756  if( coverfound )
5757  {
5758  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5759  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5760  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5761  */
5762  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5763  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5764  }
5765  }
5766 
5767  TERMINATE:
5768  /* frees temporary memory */
5769  SCIPfreeBufferArray(scip, &noncovervars);
5770  SCIPfreeBufferArray(scip, &covervars);
5771  SCIPfreeBufferArray(scip, &solvals);
5772 
5773  return SCIP_OKAY;
5774 }
5775 
5776 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5778  SCIP* scip, /**< SCIP data structure */
5779  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5780  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5781  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5782  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5783  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5784  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5785  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5786  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5787  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5788  int* ncuts /**< pointer to add up the number of found cuts */
5789  )
5790 {
5791  SCIP_VAR** binvars;
5792  SCIP_VAR** consvars;
5793  SCIP_Real* binvals;
5794  SCIP_Longint* consvals;
5795  SCIP_Longint minact;
5796  SCIP_Longint maxact;
5797  SCIP_Real intscalar;
5798  SCIP_Bool success;
5799  int nbinvars;
5800  int nconsvars;
5801  int i;
5802 
5803  int* tmpindices;
5804  int tmp;
5805  SCIP_CONSHDLR* conshdlr;
5806  SCIP_CONSHDLRDATA* conshdlrdata;
5807  SCIP_Bool noknapsackconshdlr;
5808  SCIP_Bool usegubs;
5809 
5810  assert(nknapvars > 0);
5811  assert(knapvars != NULL);
5812  assert(cutoff != NULL);
5813 
5814  tmpindices = NULL;
5815 
5816  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5817  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5818 
5819  binvars = SCIPgetVars(scip);
5820 
5821  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5822  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5823 
5824  *cutoff = FALSE;
5825 
5826  if( nbinvars == 0 )
5827  return SCIP_OKAY;
5828 
5829  /* set up data structures */
5830  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5831  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5832 
5833  /* get conshdlrdata to use cleared memory */
5834  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5835  if( conshdlr == NULL )
5836  {
5837  noknapsackconshdlr = TRUE;
5838  usegubs = DEFAULT_USEGUBS;
5839 
5840  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5841  BMSclearMemoryArray(binvals, nbinvars);
5842  }
5843  else
5844  {
5845  noknapsackconshdlr = FALSE;
5846  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5847  assert(conshdlrdata != NULL);
5848  usegubs = conshdlrdata->usegubs;
5849 
5850  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5851 
5852  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5853  * change their types to SCIP_VARTYPE_BINARY during presolving
5854  */
5855  if( conshdlrdata->reals1size == 0 )
5856  {
5857  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5858  conshdlrdata->reals1size = 1;
5859  conshdlrdata->reals1[0] = 0.0;
5860  }
5861 
5862  assert(conshdlrdata->reals1size > 0);
5863 
5864  /* next if condition should normally not be true, because it means that presolving has created more binary
5865  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5866  * transform all integers into their binary representation then it maybe happens
5867  */
5868  if( conshdlrdata->reals1size < nbinvars )
5869  {
5870  int oldsize = conshdlrdata->reals1size;
5871 
5872  conshdlrdata->reals1size = nbinvars;
5873  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5874  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5875  }
5876  binvals = conshdlrdata->reals1;
5877 
5878  /* check for cleared array, all entries have to be zero */
5879 #ifndef NDEBUG
5880  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5881  {
5882  assert(binvals[tmp] == 0);
5883  }
5884 #endif
5885  }
5886 
5887  tmp = 0;
5888 
5889  /* relax continuous knapsack constraint:
5890  * 1. make all variables binary:
5891  * if x_j is continuous or integer variable substitute:
5892  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5893  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5894  * 2. convert coefficients of all variables to positive integers:
5895  * - scale all coefficients a_j to a~_j integral
5896  * - substitute x~_j = 1 - x_j if a~_j < 0
5897  */
5898 
5899  /* replace integer and continuous variables with binary variables */
5900  for( i = 0; i < nknapvars; i++ )
5901  {
5902  SCIP_VAR* var;
5903 
5904  var = knapvars[i];
5905 
5906  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5907  {
5908  SCIP_Real solval;
5909  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5910 
5911  solval = SCIPgetSolVal(scip, sol, var);
5912 
5913  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5914  if( SCIPisFeasLT(scip, solval, 0.0 )
5915  || SCIPisFeasGT(scip, solval, 1.0) )
5916  {
5917  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5918  solval, SCIPvarGetName(var));
5919  goto TERMINATE;
5920  }
5921 
5922  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5923  if( !noknapsackconshdlr )
5924  {
5925  assert(tmpindices != NULL);
5926 
5927  tmpindices[tmp] = SCIPvarGetProbindex(var);
5928  ++tmp;
5929  }
5930  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5931  }
5932  else if( valscale * knapvals[i] > 0.0 )
5933  {
5934  SCIP_VAR** zvlb;
5935  SCIP_Real* bvlb;
5936  SCIP_Real* dvlb;
5937  SCIP_Real bestlbsol;
5938  int bestlbtype;
5939  int nvlb;
5940  int j;
5941 
5942  /* a_j > 0: substitution with lb or vlb */
5943  nvlb = SCIPvarGetNVlbs(var);
5944  zvlb = SCIPvarGetVlbVars(var);
5945  bvlb = SCIPvarGetVlbCoefs(var);
5946  dvlb = SCIPvarGetVlbConstants(var);
5947 
5948  /* search for lb or vlb with maximal bound value */
5949  bestlbsol = SCIPvarGetLbGlobal(var);
5950  bestlbtype = -1;
5951  for( j = 0; j < nvlb; j++ )
5952  {
5953  /* use only numerical stable vlb with binary variable z */
5954  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5955  {
5956  SCIP_Real vlbsol;
5957 
5958  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5959  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5960  {
5961  *cutoff = TRUE;
5962  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5964  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5965  goto TERMINATE;
5966  }
5967 
5968  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5969  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5970  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5971  {
5972  bestlbsol = vlbsol;
5973  bestlbtype = j;
5974  }
5975  }
5976  }
5977 
5978  /* if no lb or vlb with binary variable was found, we have to abort */
5979  if( SCIPisInfinity(scip, -bestlbsol) )
5980  goto TERMINATE;
5981 
5982  if( bestlbtype == -1 )
5983  {
5984  rhs -= valscale * knapvals[i] * bestlbsol;
5985  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5986  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5987  }
5988  else
5989  {
5990  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5991  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5992  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5993 
5994  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5995  goto TERMINATE;
5996 
5997  if( !noknapsackconshdlr )
5998  {
5999  assert(tmpindices != NULL);
6000 
6001  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6002  ++tmp;
6003  }
6004  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6005  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6006  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6007  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6008  }
6009  }
6010  else
6011  {
6012  SCIP_VAR** zvub;
6013  SCIP_Real* bvub;
6014  SCIP_Real* dvub;
6015  SCIP_Real bestubsol;
6016  int bestubtype;
6017  int nvub;
6018  int j;
6019 
6020  assert(valscale * knapvals[i] < 0.0);
6021 
6022  /* a_j < 0: substitution with ub or vub */
6023  nvub = SCIPvarGetNVubs(var);
6024  zvub = SCIPvarGetVubVars(var);
6025  bvub = SCIPvarGetVubCoefs(var);
6026  dvub = SCIPvarGetVubConstants(var);
6027 
6028  /* search for ub or vub with minimal bound value */
6029  bestubsol = SCIPvarGetUbGlobal(var);
6030  bestubtype = -1;
6031  for( j = 0; j < nvub; j++ )
6032  {
6033  /* use only numerical stable vub with active binary variable z */
6034  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6035  {
6036  SCIP_Real vubsol;
6037 
6038  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6039  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6040  {
6041  *cutoff = TRUE;
6042  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6044  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6045  goto TERMINATE;
6046  }
6047 
6048  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6049  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6050  if( SCIPisLE(scip, vubsol, bestubsol) )
6051  {
6052  bestubsol = vubsol;
6053  bestubtype = j;
6054  }
6055  }
6056  }
6057 
6058  /* if no ub or vub with binary variable was found, we have to abort */
6059  if( SCIPisInfinity(scip, bestubsol) )
6060  goto TERMINATE;
6061 
6062  if( bestubtype == -1 )
6063  {
6064  rhs -= valscale * knapvals[i] * bestubsol;
6065  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6066  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6067  }
6068  else
6069  {
6070  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6071  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6072  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6073 
6074  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6075  goto TERMINATE;
6076 
6077  if( !noknapsackconshdlr )
6078  {
6079  assert(tmpindices != NULL);
6080 
6081  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6082  ++tmp;
6083  }
6084  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6085  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6086  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6087  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6088  }
6089  }
6090  }
6091 
6092  /* convert coefficients of all (now binary) variables to positive integers:
6093  * - make all coefficients integral
6094  * - make all coefficients positive (substitute negated variable)
6095  */
6096  nconsvars = 0;
6097 
6098  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6099  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6100  */
6102  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6103  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6104 
6105  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6106  if( !success )
6107  intscalar = 1.0;
6108 
6109  /* make all coefficients integral and positive:
6110  * - scale a~_j = a_j * intscalar
6111  * - substitute x~_j = 1 - x_j if a~_j < 0
6112  */
6113  rhs = rhs * intscalar;
6114 
6115  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6116  minact = 0;
6117  maxact = 0;
6118  for( i = 0; i < nbinvars; i++ )
6119  {
6120  SCIP_VAR* var;
6121  SCIP_Longint val;
6122 
6123  val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6124  if( val == 0 )
6125  continue;
6126 
6127  if( val > 0 )
6128  {
6129  var = binvars[i];
6130  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6131  val, SCIPvarGetName(var), binvals[i], rhs);
6132  }
6133  else
6134  {
6135  assert(val < 0);
6136 
6137  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6138  val = -val; /*lint !e2704*/
6139  rhs += val;
6140  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6141  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6142  }
6143 
6144  if( SCIPvarGetLbLocal(var) > 0.5 )
6145  minact += val;
6146  if( SCIPvarGetUbLocal(var) > 0.5 )
6147  maxact += val;
6148  consvals[nconsvars] = val;
6149  consvars[nconsvars] = var;
6150  nconsvars++;
6151  }
6152 
6153  if( nconsvars > 0 )
6154  {
6155  SCIP_Longint capacity;
6156 
6157  assert(consvars != NULL);
6158  assert(consvals != NULL);
6159  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6160 
6161 #ifdef SCIP_DEBUG
6162  {
6163  SCIP_Real act;
6164 
6165  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6166  act = 0.0;
6167  for( i = 0; i < nconsvars; ++i )
6168  {
6169  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6170  SCIPgetSolVal(scip, sol, consvars[i]));
6171  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6172  }
6173  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6174  capacity, rhs, act, minact, maxact);
6175  }
6176 #endif
6177 
6178  if( minact > capacity )
6179  {
6180  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6181  *cutoff = TRUE;
6182  goto TERMINATE;
6183  }
6184 
6185  if( maxact > capacity )
6186  {
6187  /* separate lifted cut from relaxed knapsack constraint */
6188  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6189  }
6190  }
6191 
6192  TERMINATE:
6193  /* free data structures */
6194  if( noknapsackconshdlr)
6195  {
6196  SCIPfreeBufferArray(scip, &binvals);
6197  }
6198  else
6199  {
6200  /* clear binvals */
6201  for( --tmp; tmp >= 0; --tmp)
6202  {
6203  assert(tmpindices != NULL);
6204  binvals[tmpindices[tmp]] = 0;
6205  }
6206  SCIPfreeBufferArray(scip, &tmpindices);
6207  }
6208  SCIPfreeBufferArray(scip, &consvals);
6209  SCIPfreeBufferArray(scip, &consvars);
6210 
6211  return SCIP_OKAY;
6212 }
6213 
6214 /** separates given knapsack constraint */
6215 static
6217  SCIP* scip, /**< SCIP data structure */
6218  SCIP_CONS* cons, /**< knapsack constraint */
6219  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6220  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6221  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6222  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6223  int* ncuts /**< pointer to add up the number of found cuts */
6224  )
6225 {
6226  SCIP_CONSDATA* consdata;
6227  SCIP_Bool violated;
6228 
6229  assert(ncuts != NULL);
6230  assert(cutoff != NULL);
6231  *cutoff = FALSE;
6232 
6233  consdata = SCIPconsGetData(cons);
6234  assert(consdata != NULL);
6235 
6236  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6237 
6238  /* check knapsack constraint itself for feasibility */
6239  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6240 
6241  if( violated )
6242  {
6243  /* add knapsack constraint as LP row to the LP */
6244  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6245  (*ncuts)++;
6246  }
6247  else if( sepacuts )
6248  {
6249  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6250  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6251  }
6252 
6253  return SCIP_OKAY;
6254 }
6255 
6256 /** adds coefficient to constraint data */
6257 static
6259  SCIP* scip, /**< SCIP data structure */
6260  SCIP_CONS* cons, /**< knapsack constraint */
6261  SCIP_VAR* var, /**< variable to add to knapsack */
6262  SCIP_Longint weight /**< weight of variable in knapsack */
6263  )
6264 {
6265  SCIP_CONSDATA* consdata;
6267  consdata = SCIPconsGetData(cons);
6268  assert(consdata != NULL);
6269  assert(SCIPvarIsBinary(var));
6270  assert(weight > 0);
6271 
6272  /* add the new coefficient to the LP row */
6273  if( consdata->row != NULL )
6274  {
6275  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6276  }
6277 
6278  /* check for fixed variable */
6279  if( SCIPvarGetLbGlobal(var) > 0.5 )
6280  {
6281  /* variable is fixed to one: reduce capacity */
6282  consdata->capacity -= weight;
6283  }
6284  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6285  {
6286  SCIP_Bool negated;
6287 
6288  /* get binary representative of variable */
6289  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6290 
6291  /* insert coefficient */
6292  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6293  consdata->vars[consdata->nvars] = var;
6294  consdata->weights[consdata->nvars] = weight;
6295  consdata->nvars++;
6296 
6297  /* capture variable */
6298  SCIP_CALL( SCIPcaptureVar(scip, var) );
6299 
6300  /* install the rounding locks of variable */
6301  SCIP_CALL( lockRounding(scip, cons, var) );
6302 
6303  /* catch events */
6304  if( SCIPconsIsTransformed(cons) )
6305  {
6306  SCIP_CONSHDLRDATA* conshdlrdata;
6307 
6308  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6309  assert(conshdlrdata != NULL);
6310  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6312  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6313  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6314 
6315  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6316  consdata->existmultaggr = TRUE;
6317 
6318  /* mark constraint to be propagated and presolved */
6319  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6320  consdata->presolvedtiming = 0;
6321  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6322  }
6323 
6324  /* update weight sums */
6325  updateWeightSums(consdata, var, weight);
6326 
6327  consdata->sorted = FALSE;
6328  consdata->cliquepartitioned = FALSE;
6329  consdata->negcliquepartitioned = FALSE;
6330  consdata->merged = FALSE;
6331  }
6332 
6333  return SCIP_OKAY;
6334 }
6335 
6336 /** deletes coefficient at given position from constraint data */
6337 static
6339  SCIP* scip, /**< SCIP data structure */
6340  SCIP_CONS* cons, /**< knapsack constraint */
6341  int pos /**< position of coefficient to delete */
6342  )
6343 {
6344  SCIP_CONSDATA* consdata;
6345  SCIP_VAR* var;
6347  consdata = SCIPconsGetData(cons);
6348  assert(consdata != NULL);
6349  assert(0 <= pos && pos < consdata->nvars);
6350 
6351  var = consdata->vars[pos];
6352  assert(var != NULL);
6353  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6354 
6355  /* delete the coefficient from the LP row */
6356  if( consdata->row != NULL )
6357  {
6358  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6359  }
6360 
6361  /* remove the rounding locks of variable */
6362  SCIP_CALL( unlockRounding(scip, cons, var) );
6363 
6364  /* drop events and mark constraint to be propagated and presolved */
6365  if( SCIPconsIsTransformed(cons) )
6366  {
6367  SCIP_CONSHDLRDATA* conshdlrdata;
6368 
6369  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6370  assert(conshdlrdata != NULL);
6372  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6373  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6374 
6375  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6376  consdata->presolvedtiming = 0;
6377  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6378  }
6379 
6380  /* decrease weight sums */
6381  updateWeightSums(consdata, var, -consdata->weights[pos]);
6382 
6383  /* move the last variable to the free slot */
6384  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6385  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6386  if( consdata->eventdata != NULL )
6387  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6388 
6389  /* release variable */
6390  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6391 
6392  /* try to use old clique partitions */
6393  if( consdata->cliquepartitioned )
6394  {
6395  assert(consdata->cliquepartition != NULL);
6396  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6397  * change the clique number */
6398  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6399  {
6400  int oldcliqenum;
6401 
6402  oldcliqenum = consdata->cliquepartition[pos];
6403  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6404 
6405  /* the following if and else cases assure that we have increasing clique numbers */
6406  if( consdata->cliquepartition[pos] > pos )
6407  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6408  else
6409  {
6410  int i;
6411  int cliquenumbefore;
6412 
6413  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6414  * occurs the same as the old one is still in the cliquepartition */
6415  if( oldcliqenum > consdata->cliquepartition[pos] )
6416  {
6417  for( i = 0; i < consdata->nvars; ++i )
6418  if( oldcliqenum == consdata->cliquepartition[i] )
6419  break;
6420  else if( oldcliqenum < consdata->cliquepartition[i] )
6421  {
6422  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6423  break;
6424  }
6425  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6426  * the biggest index, so decrease the number of cliques
6427  */
6428  if( i == consdata->nvars )
6429  --(consdata->ncliques);
6430  }
6431  /* if the old clique number was smaller than the new one we have to check the front for an element with
6432  * clique number minus 1 */
6433  else if( oldcliqenum < consdata->cliquepartition[pos] )
6434  {
6435  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6436  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6437 
6438  if( i < cliquenumbefore )
6439  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6440  }
6441  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6442  else if( pos == consdata->nvars - 1)
6443  {
6444  cliquenumbefore = consdata->cliquepartition[pos];
6445  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6446 
6447  if( i < cliquenumbefore )
6448  --(consdata->ncliques);
6449  }
6450  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6451  }
6452  }
6453  else
6454  --(consdata->ncliques);
6455  }
6456 
6457  if( consdata->negcliquepartitioned )
6458  {
6459  assert(consdata->negcliquepartition != NULL);
6460  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6461  * change the clique number */
6462  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6463  {
6464  int oldcliqenum;
6465 
6466  oldcliqenum = consdata->negcliquepartition[pos];
6467  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6468 
6469  /* the following if and else cases assure that we have increasing clique numbers */
6470  if( consdata->negcliquepartition[pos] > pos )
6471  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6472  else
6473  {
6474  int i;
6475  int cliquenumbefore;
6476 
6477  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6478  * occurs, the same as the old one occurs */
6479  if( oldcliqenum > consdata->negcliquepartition[pos] )
6480  {
6481  for( i = 0; i < consdata->nvars; ++i )
6482  if( oldcliqenum == consdata->negcliquepartition[i] )
6483  break;
6484  else if( oldcliqenum < consdata->negcliquepartition[i] )
6485  {
6486  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6487  break;
6488  }
6489  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6490  * the biggest index, so decrease the number of negated cliques
6491  */
6492  if( i == consdata->nvars )
6493  --(consdata->nnegcliques);
6494  }
6495  /* if the old clique number was smaller than the new one we have to check the front for an element with
6496  * clique number minus 1 */
6497  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6498  {
6499  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6500  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6501 
6502  if( i < cliquenumbefore )
6503  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6504  }
6505  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6506  else if( pos == consdata->nvars - 1)
6507  {
6508  cliquenumbefore = consdata->negcliquepartition[pos];
6509  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6510 
6511  if( i < cliquenumbefore )
6512  --(consdata->nnegcliques);
6513  }
6514  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6515  }
6516  }
6517  else
6518  --(consdata->nnegcliques);
6519  }
6520 
6521  --(consdata->nvars);
6522 
6523  return SCIP_OKAY;
6524 }
6525 
6526 /** removes all items with weight zero from knapsack constraint */
6527 static
6529  SCIP* scip, /**< SCIP data structure */
6530  SCIP_CONS* cons /**< knapsack constraint */
6531  )
6532 {
6533  SCIP_CONSDATA* consdata;
6534  int v;
6535 
6536  consdata = SCIPconsGetData(cons);
6537  assert(consdata != NULL);
6538 
6539  for( v = consdata->nvars-1; v >= 0; --v )
6540  {
6541  if( consdata->weights[v] == 0 )
6542  {
6543  SCIP_CALL( delCoefPos(scip, cons, v) );
6544  }
6545  }
6546 
6547  return SCIP_OKAY;
6548 }
6549 
6550 /* perform deletion of variables in all constraints of the constraint handler */
6551 static
6553  SCIP* scip, /**< SCIP data structure */
6554  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6555  SCIP_CONS** conss, /**< array of constraints */
6556  int nconss /**< number of constraints */
6557  )
6558 {
6559  SCIP_CONSDATA* consdata;
6560  int i;
6561  int v;
6562 
6563  assert(scip != NULL);
6564  assert(conshdlr != NULL);
6565  assert(conss != NULL);
6566  assert(nconss >= 0);
6567  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6568 
6569  /* iterate over all constraints */
6570  for( i = 0; i < nconss; i++ )
6571  {
6572  consdata = SCIPconsGetData(conss[i]);
6573 
6574  /* constraint is marked, that some of its variables were deleted */
6575  if( consdata->varsdeleted )
6576  {
6577  /* iterate over all variables of the constraint and delete them from the constraint */
6578  for( v = consdata->nvars - 1; v >= 0; --v )
6579  {
6580  if( SCIPvarIsDeleted(consdata->vars[v]) )
6581  {
6582  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6583  }
6584  }
6585  consdata->varsdeleted = FALSE;
6586  }
6587  }
6588 
6589  return SCIP_OKAY;
6590 }
6591 
6592 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6593 static
6595  SCIP* scip, /**< SCIP data structure */
6596  SCIP_CONS* cons, /**< knapsack constraint */
6597  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6598  )
6599 {
6600  SCIP_CONSDATA* consdata;
6601  int v;
6602  int prev;
6603 
6604  assert(scip != NULL);
6605  assert(cons != NULL);
6606  assert(cutoff != NULL);
6607 
6608  consdata = SCIPconsGetData(cons);
6609  assert(consdata != NULL);
6610 
6611  *cutoff = FALSE;
6612 
6613  if( consdata->merged )
6614  return SCIP_OKAY;
6615 
6616  if( consdata->nvars <= 1 )
6617  {
6618  consdata->merged = TRUE;
6619  return SCIP_OKAY;
6620  }
6621 
6622  assert(consdata->vars != NULL || consdata->nvars == 0);
6623 
6624  /* sorting array after indices of variables, that's only for faster merging */
6625  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6626  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6627 
6628  /* knapsack-sorting (decreasing weights) now lost */
6629  consdata->sorted = FALSE;
6630 
6631  v = consdata->nvars - 1;
6632  prev = v - 1;
6633  /* loop backwards through the items: deletion only affects rear items */
6634  while( prev >= 0 )
6635  {
6636  SCIP_VAR* var1;
6637  SCIP_VAR* var2;
6638  SCIP_Bool negated1;
6639  SCIP_Bool negated2;
6640 
6641  negated1 = FALSE;
6642  negated2 = FALSE;
6643 
6644  var1 = consdata->vars[v];
6645  assert(SCIPvarIsBinary(var1));
6646  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6648  {
6649  var1 = SCIPvarGetNegatedVar(var1);
6650  negated1 = TRUE;
6651  }
6652  assert(var1 != NULL);
6653 
6654  var2 = consdata->vars[prev];
6655  assert(SCIPvarIsBinary(var2));
6656  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6658  {
6659  var2 = SCIPvarGetNegatedVar(var2);
6660  negated2 = TRUE;
6661  }
6662  assert(var2 != NULL);
6663 
6664  if( var1 == var2 )
6665  {
6666  /* both variables are either active or negated */
6667  if( negated1 == negated2 )
6668  {
6669  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6670  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6671  SCIP_CALL( delCoefPos(scip, cons, v) );
6672  }
6673  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6674  * and delete item of smaller weight
6675  */
6676  else if( consdata->weights[v] == consdata->weights[prev] )
6677  {
6678  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6679  consdata->capacity -= consdata->weights[v];
6680  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6681  SCIP_CALL( delCoefPos(scip, cons, prev) );
6682 
6683  --prev;
6684  }
6685  else if( consdata->weights[v] < consdata->weights[prev] )
6686  {
6687  consdata->capacity -= consdata->weights[v];
6688  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6689  assert(consdata->weights[prev] > 0);
6690  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6691  }
6692  else
6693  {
6694  consdata->capacity -= consdata->weights[prev];
6695  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6696  assert(consdata->weights[v] > 0);
6697  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6698  /* restore order iff necessary */
6699  if( consdata->nvars != v ) /* otherwise the order still stands */
6700  {
6701  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6702  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6703  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6704  --prev;
6705  else /* we need to let v at the same position*/
6706  {
6707  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6708  /* don't decrease v, the same variable may exist up front */
6709  --prev;
6710  continue;
6711  }
6712  }
6713  }
6714  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6715  }
6716  v = prev;
6717  --prev;
6718  }
6719 
6720  consdata->merged = TRUE;
6721 
6722  /* check infeasibility */
6723  if( consdata->onesweightsum > consdata->capacity )
6724  {
6725  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6726  *cutoff = TRUE;
6727  return SCIP_OKAY;
6728  }
6729 
6730  return SCIP_OKAY;
6731 }
6732 
6733 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6734  * fixings (dual reductions)
6735  */
6736 static
6738  SCIP* scip, /**< SCIP data structure */
6739  SCIP_CONS* cons, /**< knapsack constraint */
6740  int* nfixedvars, /**< pointer to count number of fixings */
6741  int* ndelconss, /**< pointer to count number of deleted constraints */
6742  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6743  )
6744 {
6745  SCIP_CONSDATA* consdata;
6746  SCIP_VAR** vars;
6747  SCIP_Real* profits;
6748  int* solitems;
6749  int* nonsolitems;
6750  int* items;
6751  SCIP_Real solval;
6752  SCIP_Bool infeasible;
6753  SCIP_Bool tightened;
6754  SCIP_Bool applicable;
6755  int nsolitems;
6756  int nnonsolitems;
6757  int nvars;
6758  int v;
6759 
6760  assert(!SCIPconsIsModifiable(cons));
6761 
6762  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6763  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6764  * added to the problems have the check flag set to FALSE
6765  */
6766  if( !SCIPconsIsChecked(cons) )
6767  return SCIP_OKAY;
6768 
6769  consdata = SCIPconsGetData(cons);
6770  assert(consdata != NULL);
6771 
6772  nvars = consdata->nvars;
6773  vars = consdata->vars;
6774 
6775  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6776  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6777  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6778  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6779 
6780  applicable = TRUE;
6781 
6782  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6783  * collect object values which are the profits of the knapsack problem
6784  */
6785  for( v = 0; v < nvars; ++v )
6786  {
6787  SCIP_VAR* var;
6788  SCIP_Bool negated;
6789 
6790  var = vars[v];
6791  assert(var != NULL);
6792 
6793  /* the variable should not be (globally) fixed */
6794  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6795 
6798  {
6799  applicable = FALSE;
6800  break;
6801  }
6802 
6803  negated = FALSE;
6804 
6805  /* get the active variable */
6806  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6807  assert(SCIPvarIsActive(var));
6808 
6809  if( negated )
6810  profits[v] = SCIPvarGetObj(var);
6811  else
6812  profits[v] = -SCIPvarGetObj(var);
6813 
6814  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6815  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6816  items[v] = v;
6817  }
6818 
6819  if( applicable )
6820  {
6821  SCIP_Bool success;
6822 
6823  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6824  SCIPdebugPrintCons(scip, cons, NULL);
6825 
6826  /* solve knapsack problem exactly */
6827  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6828  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6829 
6830  if( success )
6831  {
6832  SCIP_VAR* var;
6833 
6834  /* apply solution of the knapsack as dual reductions */
6835  for( v = 0; v < nsolitems; ++v )
6836  {
6837  var = vars[solitems[v]];
6838  assert(var != NULL);
6839 
6840  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6842  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6843  assert(!infeasible);
6844  assert(tightened);
6845  (*nfixedvars)++;
6846  }
6847 
6848  for( v = 0; v < nnonsolitems; ++v )
6849  {
6850  var = vars[nonsolitems[v]];
6851  assert(var != NULL);
6852 
6853  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6855  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6856  assert(!infeasible);
6857  assert(tightened);
6858  (*nfixedvars)++;
6859  }
6860 
6861  SCIP_CALL( SCIPdelCons(scip, cons) );
6862  (*ndelconss)++;
6863  (*deleted) = TRUE;
6864  }
6865  }
6866 
6867  SCIPfreeBufferArray(scip, &nonsolitems);
6868  SCIPfreeBufferArray(scip, &solitems);
6869  SCIPfreeBufferArray(scip, &items);
6870  SCIPfreeBufferArray(scip, &profits);
6871 
6872  return SCIP_OKAY;
6873 }
6874 
6875 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6876  * constraint enters the LP by setting the initial and separated flag to FALSE
6877  */
6878 static
6880  SCIP* scip, /**< SCIP data structure */
6881  SCIP_CONS* cons, /**< knapsack constraint */
6882  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6883  )
6884 {
6885  SCIP_CONSDATA* consdata;
6886  SCIP_VAR** vars;
6887  SCIP_VAR* var;
6888  SCIP_Real offset;
6889  SCIP_Real scale;
6890  SCIP_Real objval;
6891  SCIP_Bool applicable;
6892  SCIP_Bool negated;
6893  int nobjvars;
6894  int nvars;
6895  int v;
6896 
6897  assert(scip != NULL);
6898  assert(cons != NULL);
6899  assert(conshdlrdata != NULL);
6900 
6901  consdata = SCIPconsGetData(cons);
6902  assert(consdata != NULL);
6903 
6904  nvars = consdata->nvars;
6905  nobjvars = SCIPgetNObjVars(scip);
6906 
6907  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6908  * and/or separated flag is set to FALSE
6909  */
6910  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6911  return SCIP_OKAY;
6912 
6913  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6914  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6915  */
6916  if( nobjvars == 0 )
6917  return SCIP_OKAY;
6918 
6919  vars = consdata->vars;
6920  assert(vars != NULL);
6921 
6922  applicable = TRUE;
6923  offset = 0.0;
6924  scale = 1.0;
6925 
6926  for( v = 0; v < nvars && applicable; ++v )
6927  {
6928  negated = FALSE;
6929  var = vars[v];
6930  assert(var != NULL);
6931 
6932  if( SCIPvarIsNegated(var) )
6933  {
6934  negated = TRUE;
6935  var = SCIPvarGetNegatedVar(var);
6936  assert(var != NULL);
6937  }
6938 
6939  objval = SCIPvarGetObj(var);
6940 
6941  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6942  if( SCIPisZero(scip, objval) )
6943  applicable = FALSE;
6944  else
6945  {
6946  SCIP_Real weight;
6947 
6948  weight = (SCIP_Real)consdata->weights[v];
6949 
6950  if( negated )
6951  {
6952  if( v == 0 )
6953  {
6954  /* the first variable defines the scale */
6955  scale = weight / -objval;
6956 
6957  offset += weight;
6958  }
6959  else if( SCIPisEQ(scip, -objval * scale, weight) )
6960  offset += weight;
6961  else
6962  applicable = FALSE;
6963  }
6964  else if( v == 0 )
6965  {
6966  /* the first variable define the scale */
6967  scale = weight / objval;
6968  }
6969  else if( !SCIPisEQ(scip, objval * scale, weight) )
6970  applicable = FALSE;
6971  }
6972  }
6973 
6974  if( applicable )
6975  {
6976  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6977  {
6978  SCIP_Real cutoffbound;
6979 
6980  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6981  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6982  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6983 
6984  cutoffbound = (consdata->capacity - offset) / scale;
6985 
6986  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6987  SCIPconsGetName(cons), cutoffbound);
6988 
6989  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6990  * still excepted
6991  */
6992  cutoffbound += SCIPcutoffbounddelta(scip);
6993 
6994  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6995  SCIPconsGetName(cons), cutoffbound);
6996 
6997  if( cutoffbound < SCIPgetCutoffbound(scip) )
6998  {
6999  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7000 
7001  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7002  }
7003  else
7004  {
7005  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7006  * propagation
7007  */
7008  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
7009  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
7010  }
7011  }
7012  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7013  {
7014  SCIP_Real lowerbound;
7015 
7016  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7017  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
7018  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
7019 
7020  lowerbound = (consdata->capacity - offset) / scale;
7021 
7022  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7023  SCIPconsGetName(cons), lowerbound);
7024 
7025  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
7026  }
7027  }
7028 
7029  return SCIP_OKAY;
7030 }
7031 
7032 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7033  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7034 static
7036  SCIP* scip, /**< SCIP data structure */
7037  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7038  SCIP_VAR** vars, /**< array for sorted variables */
7039  SCIP_Longint* weights, /**< array for sorted weights */
7040  int* cliquestartposs, /**< starting position array for each clique */
7041  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7042  )
7044  SCIP_VAR** origvars;
7045  int norigvars;
7046  SCIP_Longint* origweights;
7047  int* cliquepartition;
7048  int ncliques;
7049 
7050  SCIP_VAR*** varpointers;
7051  SCIP_Longint** weightpointers;
7052  int* cliquecount;
7053 
7054  int nextpos;
7055  int c;
7056  int v;
7057 
7058  assert(scip != NULL);
7059  assert(consdata != NULL);
7060  assert(vars != NULL);
7061  assert(weights != NULL);
7062  assert(cliquestartposs != NULL);
7063 
7064  origweights = consdata->weights;
7065  origvars = consdata->vars;
7066  norigvars = consdata->nvars;
7067 
7068  assert(origvars != NULL || norigvars == 0);
7069  assert(origweights != NULL || norigvars == 0);
7070 
7071  if( norigvars == 0 )
7072  return SCIP_OKAY;
7073 
7074  if( usenegatedclique )
7075  {
7076  assert(consdata->negcliquepartitioned);
7077 
7078  cliquepartition = consdata->negcliquepartition;
7079  ncliques = consdata->nnegcliques;
7080  }
7081  else
7082  {
7083  assert(consdata->cliquepartitioned);
7084 
7085  cliquepartition = consdata->cliquepartition;
7086  ncliques = consdata->ncliques;
7087  }
7088 
7089  assert(cliquepartition != NULL);
7090  assert(ncliques > 0);
7091 
7092  /* we first count all clique items and alloc temporary memory for a bucket sort */
7093  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7094  BMSclearMemoryArray(cliquecount, ncliques);
7095 
7096  /* first we count for each clique the number of elements */
7097  for( v = norigvars - 1; v >= 0; --v )
7098  {
7099  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7100  ++(cliquecount[cliquepartition[v]]);
7101  }
7102 
7103  /*@todo: maybe it is better to put largest cliques up front */
7104 
7105 #ifndef NDEBUG
7106  BMSclearMemoryArray(vars, norigvars);
7107  BMSclearMemoryArray(weights, norigvars);
7108 #endif
7109  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7110  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7111 
7112  nextpos = 0;
7113  /* now we initialize all start pointers for each clique, so they will be ordered */
7114  for( c = 0; c < ncliques; ++c )
7115  {
7116  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7117  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7118  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7119  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7120  * vars[7]
7121  *
7122  */
7123  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7124  cliquestartposs[c] = nextpos;
7125  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7126  assert(cliquecount[c] > 0);
7127  nextpos += cliquecount[c];
7128  assert(nextpos > 0);
7129  }
7130  assert(nextpos == norigvars);
7131  cliquestartposs[c] = nextpos;
7132 
7133  /* now we copy all variable and weights to the right order */
7134  for( v = 0; v < norigvars; ++v )
7135  {
7136  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7137  ++(varpointers[cliquepartition[v]]);
7138  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7139  ++(weightpointers[cliquepartition[v]]);
7140  }
7141 #ifndef NDEBUG
7142  for( v = 0; v < norigvars; ++v )
7143  {
7144  assert(vars[v] != NULL);
7145  assert(weights[v] > 0);
7146  }
7147 #endif
7148 
7149  /* free temporary memory */
7150  SCIPfreeBufferArray(scip, &weightpointers);
7151  SCIPfreeBufferArray(scip, &varpointers);
7152  SCIPfreeBufferArray(scip, &cliquecount);
7153 
7154  return SCIP_OKAY;
7155 }
7156 
7157 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7158 static
7160  SCIP* scip, /**< SCIP data structure */
7161  SCIP_CONS* cons, /**< knapsack constraint */
7162  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7163  * information is not needed; in this case, we apply all fixings
7164  * instead of stopping after the first infeasible one */
7165  )
7166 {
7167  SCIP_CONSDATA* consdata;
7168  int v;
7169 
7170  assert(scip != NULL);
7171  assert(cons != NULL);
7172 
7173  consdata = SCIPconsGetData(cons);
7174  assert(consdata != NULL);
7175  assert(consdata->nvars == 0 || consdata->vars != NULL);
7176 
7177  if( cutoff != NULL )
7178  *cutoff = FALSE;
7179 
7180  SCIPdebugMsg(scip, "apply fixings:\n");
7181  SCIPdebugPrintCons(scip, cons, NULL);
7182 
7183  /* check infeasibility */
7184  if ( consdata->onesweightsum > consdata->capacity )
7185  {
7186  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7187 
7188  if( cutoff != NULL )
7189  *cutoff = TRUE;
7190 
7191  return SCIP_OKAY;
7192  }
7193 
7194  /* all multi-aggregations should be resolved */
7195  consdata->existmultaggr = FALSE;
7196 
7197  v = 0;
7198  while( v < consdata->nvars )
7199  {
7200  SCIP_VAR* var;
7201 
7202  var = consdata->vars[v];
7203  assert(SCIPvarIsBinary(var));
7204 
7205  if( SCIPvarGetLbGlobal(var) > 0.5 )
7206  {
7207  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7208  consdata->capacity -= consdata->weights[v];
7209  SCIP_CALL( delCoefPos(scip, cons, v) );
7210  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7211  }
7212  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7213  {
7214  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7215  SCIP_CALL( delCoefPos(scip, cons, v) );
7216  }
7217  else
7218  {
7219  SCIP_VAR* repvar;
7220  SCIP_VAR* negvar;
7221  SCIP_VAR* workvar;
7222  SCIP_Longint weight;
7223  SCIP_Bool negated;
7224 
7225  weight = consdata->weights[v];
7226 
7227  /* get binary representative of variable */
7228  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7229  assert(repvar != NULL);
7230 
7231  /* check for multi-aggregation */
7232  if( SCIPvarIsNegated(repvar) )
7233  {
7234  workvar = SCIPvarGetNegatedVar(repvar);
7235  assert(workvar != NULL);
7236  negated = TRUE;
7237  }
7238  else
7239  {
7240  workvar = repvar;
7241  negated = FALSE;
7242  }
7243 
7244  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7245  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7246  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7247  *
7248  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7249  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7250  *
7251  * The explanation for the following block:
7252  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7253  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7254  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7255  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7256  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7257  * 2) For all replacement variable we check:
7258  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7259  * capacity -= weight * a_i caused by the negation of y_i.
7260  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7261  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7262  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7263  * weight in this case.
7264  */
7265  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7266  {
7267  SCIP_VAR** aggrvars;
7268  SCIP_Real* aggrscalars;
7269  SCIP_Real aggrconst;
7270  int naggrvars;
7271  int i;
7272 
7273  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7274  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7275  aggrvars = SCIPvarGetMultaggrVars(workvar);
7276  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7277  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7278  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7279 
7280  if( !SCIPisIntegral(scip, weight * aggrconst) )
7281  {
7282  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7283  return SCIP_ERROR;
7284  }
7285 
7286  /* if workvar was negated, we have to flip the weight */
7287  if( negated )
7288  weight *= -1;
7289 
7290  for( i = naggrvars - 1; i >= 0; --i )
7291  {
7292  assert(aggrvars != NULL);
7293  assert(aggrscalars != NULL);
7294 
7295  if( !SCIPvarIsBinary(aggrvars[i]) )
7296  {
7297  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7298  SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7299  return SCIP_ERROR;
7300  }
7301  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7302  {
7303  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7304  return SCIP_ERROR;
7305  }
7306  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7307  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7308  {
7309  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7310  assert(negvar != NULL);
7311  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7312  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7313  }
7314  else
7315  {
7316  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7317  }
7318  }
7319  /* delete old coefficient */
7320  SCIP_CALL( delCoefPos(scip, cons, v) );
7321 
7322  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7323  if( negated )
7324  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7325  else
7326  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7327 
7328  if( consdata->capacity < 0 )
7329  {
7330  if( cutoff != NULL )
7331  {
7332  *cutoff = TRUE;
7333  break;
7334  }
7335  }
7336  }
7337  /* check, if the variable should be replaced with the representative */
7338  else if( repvar != var )
7339  {
7340  /* delete old (aggregated) variable */
7341  SCIP_CALL( delCoefPos(scip, cons, v) );
7342 
7343  /* add representative instead */
7344  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7345  }
7346  else
7347  ++v;
7348  }
7349  }
7350  assert(consdata->onesweightsum == 0);
7351 
7352  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7353  SCIPdebugPrintCons(scip, cons, NULL);
7354 
7355  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7356  * clean up the constraint
7357  */
7358  if( cutoff != NULL && !(*cutoff) )
7359  {
7360  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7361  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7362  SCIPdebugPrintCons(scip, cons, NULL);
7363  }
7364 
7365  return SCIP_OKAY;
7366 }
7367 
7368 
7369 /** propagation method for knapsack constraints */
7370 static
7372  SCIP* scip, /**< SCIP data structure */
7373  SCIP_CONS* cons, /**< knapsack constraint */
7374  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7375  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7376  int* nfixedvars, /**< pointer to count number of fixings */
7377  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7378  )
7380  SCIP_CONSDATA* consdata;
7381  SCIP_Bool infeasible;
7382  SCIP_Bool tightened;
7383  SCIP_Longint* secondmaxweights;
7384  SCIP_Longint minweightsum;
7385  SCIP_Longint residualcapacity;
7386 
7387  int nvars;
7388  int i;
7389  int nnegcliques;
7390 
7391  SCIP_VAR** myvars;
7392  SCIP_Longint* myweights;
7393  int* cliquestartposs;
7394  int* cliqueendposs;
7395  SCIP_Longint localminweightsum;
7396  SCIP_Bool foundmax;
7397  int c;
7398 
7399  assert(scip != NULL);
7400  assert(cons != NULL);
7401  assert(cutoff != NULL);
7402  assert(redundant != NULL);
7403  assert(nfixedvars != NULL);
7404 
7405  consdata = SCIPconsGetData(cons);
7406  assert(consdata != NULL);
7407 
7408  *cutoff = FALSE;
7409  *redundant = FALSE;
7410 
7411  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7412 
7413  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7414  if( !SCIPinRepropagation(scip) )
7415  {
7416  SCIP_CALL( SCIPincConsAge(scip, cons) );
7417  }
7418 
7419 #ifndef NDEBUG
7420  /* assert that only active or negated variables are present */
7421  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7422  {
7423  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7424  }
7425 #endif
7426 
7427  usenegatedclique = usenegatedclique && consdata->merged;
7428 
7429  /* init for debugging */
7430  myvars = NULL;
7431  myweights = NULL;
7432  cliquestartposs = NULL;
7433  secondmaxweights = NULL;
7434  minweightsum = 0;
7435  nvars = consdata->nvars;
7436  /* make sure, the items are sorted by non-increasing weight */
7437  sortItems(consdata);
7438 
7439  do
7440  {
7441  localminweightsum = 0;
7442 
7443  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7444  * a negated clique means, that at most one of the clique variables can be zero
7445  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7446  *
7447  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7448  * since replacing i with the element of maximal weight leads to infeasibility
7449  */
7450  if( usenegatedclique && nvars > 0 )
7451  {
7452  SCIP_CONSHDLRDATA* conshdlrdata;
7453  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7454  assert(conshdlrdata != NULL);
7455 
7456  /* compute clique partitions */
7457  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7458  nnegcliques = consdata->nnegcliques;
7459 
7460  /* if we have no real negated cliques we can stop here */
7461  if( nnegcliques == nvars )
7462  {
7463  /* run the standard algorithm that does not involve cliques */
7464  usenegatedclique = FALSE;
7465  break;
7466  }
7467 
7468  /* allocate temporary memory and initialize it */
7469  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7470  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7471  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7472  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7473  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7474  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7475 
7476  /* resort variables to avoid quadratic algorithm later on */
7477  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7478 
7479  /* save the end positions of the cliques because start positions are moved in the following loop */
7480  for( c = 0; c < nnegcliques; ++c )
7481  {
7482  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7483  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7484  }
7485 
7486  c = 0;
7487  foundmax = FALSE;
7488  i = 0;
7489 
7490  while( i < nvars )
7491  {
7492  /* ignore variables of the negated clique which are fixed to one since these are counted in
7493  * consdata->onesweightsum
7494  */
7495 
7496  /* if there are only one variable negated cliques left we can stop */
7497  if( nnegcliques - c == nvars - i )
7498  {
7499  minweightsum += localminweightsum;
7500  localminweightsum = 0;
7501  break;
7502  }
7503 
7504  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7505  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7506  * other clique variables to one
7507  */
7508  if( cliquestartposs[c] == i )
7509  {
7510  assert(myweights[i] > 0);
7511  ++c;
7512  minweightsum += localminweightsum;
7513  localminweightsum = 0;
7514  foundmax = TRUE;
7515 
7516  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7517  foundmax = FALSE;
7518 
7519  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7520  {
7521  ++i;
7522  continue;
7523  }
7524  }
7525 
7526  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7527  {
7528  assert(myweights[i] > 0);
7529 
7530  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7531  {
7532  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7533 
7534  if( !foundmax )
7535  {
7536  foundmax = TRUE;
7537 
7538  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7539  cliquestartposs[c - 1] = i;
7540  ++i;
7541 
7542  continue;
7543  }
7544  /* memorize second max weight for each clique */
7545  if( secondmaxweights[c - 1] == 0 )
7546  secondmaxweights[c - 1] = myweights[i];
7547 
7548  localminweightsum += myweights[i];
7549  }
7550  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7551  else
7552  {
7553  int v;
7554  /* fix all other variables of the negated clique to 1 */
7555  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7556  {
7557  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7558  {
7559  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7560  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7561 
7562  if( infeasible )
7563  {
7564  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7565 
7566  /* analyze the infeasibility if conflict analysis is applicable */
7568  {
7569  /* conflict analysis can only be applied in solving stage */
7570  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7571 
7572  /* initialize the conflict analysis */
7574 
7575  /* add the two variables which are fixed to zero within a negated clique */
7576  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7577  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7578 
7579  /* start the conflict analysis */
7580  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7581  }
7582  *cutoff = TRUE;
7583  break;
7584  }
7585  assert(tightened);
7586  ++(*nfixedvars);
7587  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7588  }
7589  }
7590 
7591  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7592  localminweightsum = 0;
7593  /* we can jump to the end of this clique */
7594  i = cliqueendposs[c - 1];
7595 
7596  if( *cutoff )
7597  break;
7598  }
7599  }
7600  ++i;
7601  }
7602  /* add last clique minweightsum */
7603  minweightsum += localminweightsum;
7604 
7605  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7606  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7607 
7608  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7609  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7610  {
7611  SCIP_Longint maxcliqueweight = -1LL;
7612 
7613  /* loop over cliques */
7614  for( c = 0; c < nnegcliques; ++c )
7615  {
7616  SCIP_VAR* maxvar;
7617  SCIP_Bool maxvarfixed;
7618  int endvarposclique;
7619  int startvarposclique;
7620 
7621  assert(myvars != NULL);
7622  assert(nnegcliques == consdata->nnegcliques);
7623  assert(myweights != NULL);
7624  assert(secondmaxweights != NULL);
7625  assert(cliquestartposs != NULL);
7626 
7627  endvarposclique = cliqueendposs[c];
7628  startvarposclique = cliquestartposs[c];
7629 
7630  maxvar = myvars[startvarposclique];
7631 
7632  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7633  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7634  continue;
7635 
7636  maxcliqueweight = myweights[startvarposclique];
7637  maxvarfixed = FALSE;
7638  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7639  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7640  * exceeds the capacity the maximum weight variable can be fixed to zero.
7641  */
7642  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7643  {
7644 #ifndef NDEBUG
7645  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7646 #endif
7647  assert(maxcliqueweight >= secondmaxweights[c]);
7648  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7649 
7650  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7651  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7652  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7653  assert(consdata->onesweightsum == oldonesweightsum);
7654  assert(!infeasible);
7655  assert(tightened);
7656  (*nfixedvars)++;
7657  maxvarfixed = TRUE;
7658  }
7659  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7660  * fits into the knapsack
7661  */
7662  else if( nnegcliques - c == nvars - startvarposclique )
7663  break;
7664  /* early termination of the remaining loop because no further variable fixings are possible:
7665  *
7666  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7667  * largest was set to 0) does not suffice to infer additional variable fixings because
7668  *
7669  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7670  * - their second largest elements are at least as large as the smallest weight of the knapsack
7671  */
7672  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7673  break;
7674 
7675  /* loop over items with non-maximal weight (omitting the first position) */
7676  for( i = endvarposclique; i > startvarposclique; --i )
7677  {
7678  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7679  * messed up the clique preprocessing in the previous loop to filter those variables out */
7680  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7681 
7682  /* only check variables of negated cliques for which no variable is locally fixed */
7683  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7684  {
7685  assert(maxcliqueweight >= myweights[i]);
7686  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7687 
7688  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7689  *
7690  * the maxvar was already fixed to 0 because it has a huge gain.
7691  *
7692  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7693  * since replacing i with the element of maximal weight leads to infeasibility */
7694  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7695  {
7696 #ifndef NDEBUG
7697  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7698 #endif
7699  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7700  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7701  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7702  assert(!infeasible);
7703  assert(tightened);
7704  ++(*nfixedvars);
7705  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7706 
7707  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7708  * consdata->onesweightsum
7709  */
7710  minweightsum -= myweights[i];
7711  assert(minweightsum >= 0);
7712  }
7713  else
7714  break;
7715  }
7716  }
7717 #ifndef NDEBUG
7718  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7719  for( ; i > startvarposclique; --i )
7720  {
7721  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7722  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7723 
7724  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7725  assert(varisfixed || !exceedscapacity);
7726  }
7727 #endif
7728  }
7729  }
7730  SCIPfreeBufferArray(scip, &secondmaxweights);
7731  SCIPfreeBufferArray(scip, &cliqueendposs);
7732  SCIPfreeBufferArray(scip, &cliquestartposs);
7733  SCIPfreeBufferArray(scip, &myweights);
7734  SCIPfreeBufferArray(scip, &myvars);
7735  }
7736 
7737  assert(consdata->negcliquepartitioned || minweightsum == 0);
7738  }
7739  while( FALSE );
7740 
7741  assert(usenegatedclique || minweightsum == 0);
7742  /* check, if weights of fixed variables already exceed knapsack capacity */
7743  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7744  {
7745  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7746  consdata->onesweightsum, consdata->capacity);
7747 
7748  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7749  *cutoff = TRUE;
7750 
7751  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7753  {
7754  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7755  SCIP_Longint weight;
7756 
7757  weight = 0;
7758 
7760 
7761  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7762  {
7763  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7764  {
7765  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7766  weight += consdata->weights[i];
7767  }
7768  }
7769 
7770  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7771  }
7772 
7773  return SCIP_OKAY;
7774  }
7775 
7776  /* the algorithm below is a special case of propagation involving negated cliques */
7777  if( !usenegatedclique )
7778  {
7779  assert(consdata->sorted);
7780  residualcapacity = consdata->capacity - consdata->onesweightsum;
7781 
7782  /* fix all variables to zero, that don't fit into the knapsack anymore */
7783  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7784  {
7785  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7786  * to zero
7787  */
7788  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7789  {
7790  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7791  {
7792  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7793  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7794  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7795  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7796  assert(!infeasible);
7797  assert(tightened);
7798  (*nfixedvars)++;
7799  }
7800  }
7801  }
7802  }
7803 
7804  /* check if the knapsack is now redundant */
7805  if( !SCIPconsIsModifiable(cons) )
7806  {
7807  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7808 
7809  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7810  for( i = 0; i < nvars; ++i )
7811  {
7812  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7813  {
7814  unfixedweightsum += consdata->weights[i];
7815 
7816  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7817  if( unfixedweightsum > consdata->capacity )
7818  return SCIP_OKAY;
7819  }
7820  }
7821  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7822  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7823  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7824  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7825  *redundant = TRUE;
7826  }
7827 
7828  return SCIP_OKAY;
7829 }
7830 
7831 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7832  * containing all negated variables of this knapsack constraint
7833  */
7834 static
7836  SCIP* scip, /**< SCIP data structure */
7837  SCIP_CONS* cons, /**< knapsack constraint */
7838  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7839  int* naddconss /**< pointer to count number of added constraints */
7840  )
7841 {
7842  SCIP_CONS* newcons;
7843  SCIP_CONSDATA* consdata;
7844 
7845  assert(scip != NULL);
7846  assert(cons != NULL);
7847  assert(ndelconss != NULL);
7848  assert(naddconss != NULL);
7849 
7850  consdata = SCIPconsGetData(cons);
7851  assert(consdata != NULL);
7852  assert(consdata->nvars > 1);
7853 
7854  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7855  if( consdata->nvars == 2 )
7856  {
7857  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7858 
7859  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7863  SCIPconsIsStickingAtNode(cons)) );
7864  }
7865  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7866  * containing all negated variables of the knapsack
7867  */
7868  else
7869  {
7870  SCIP_VAR** consvars;
7871 
7872  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7873 
7874  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7875  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7876 
7877  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7881  SCIPconsIsStickingAtNode(cons)) );
7882 
7883  SCIPfreeBufferArray(scip, &consvars);
7884  }
7885 
7886  SCIP_CALL( SCIPaddCons(scip, newcons) );
7887  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7888  ++(*naddconss);
7889 
7890  SCIP_CALL( SCIPdelCons(scip, cons) );
7891  ++(*ndelconss);
7892 
7893  return SCIP_OKAY;
7894 }
7895 
7896 /** delete redundant variables
7897  *
7898  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7899  *
7900  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7901  * => x4, x5 always fits into the knapsack, so we can delete them
7902  *
7903  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7904  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7905  */
7906 static
7908  SCIP* scip, /**< SCIP data structure */
7909  SCIP_CONS* cons, /**< knapsack constraint */
7910  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7911  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7912  * first which did not fit */
7913  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7914  int* nchgsides, /**< pointer to store the amount of changed sides */
7915  int* naddconss /**< pointer to count number of added constraints */
7916  )
7917 {
7918  SCIP_CONSHDLRDATA* conshdlrdata;
7919  SCIP_CONSDATA* consdata;
7920  SCIP_VAR** vars;
7921  SCIP_Longint* weights;
7922  SCIP_Longint capacity;
7923  SCIP_Longint gcd;
7924  int nvars;
7925  int w;
7926 
7927  assert(scip != NULL);
7928  assert(cons != NULL);
7929  assert(nchgcoefs != NULL);
7930  assert(nchgsides != NULL);
7931  assert(naddconss != NULL);
7932 
7933  consdata = SCIPconsGetData(cons);
7934  assert(consdata != NULL);
7935  assert(0 < frontsum && frontsum < consdata->weightsum);
7936  assert(0 < splitpos && splitpos < consdata->nvars);
7937 
7938  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7939  assert(conshdlrdata != NULL);
7940 
7941  vars = consdata->vars;
7942  weights = consdata->weights;
7943  nvars = consdata->nvars;
7944  capacity = consdata->capacity;
7945 
7946  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7947  * weight must not be sorted by their index
7948  */
7949 #ifndef NDEBUG
7950  for( w = nvars - 1; w > 0; --w )
7951  assert(weights[w] <= weights[w-1]);
7952 #endif
7953 
7954  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7955  if( consdata->nvars - 1 == splitpos )
7956  return SCIP_OKAY;
7957 
7958  assert(frontsum + weights[splitpos] > capacity);
7959 
7960  /* detect redundant variables */
7961  if( consdata->weightsum - weights[splitpos] <= capacity )
7962  {
7963  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7964  * fit
7965  */
7966  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7967 
7968  /* delete items and update capacity */
7969  for( w = nvars - 1; w > splitpos; --w )
7970  {
7971  consdata->capacity -= weights[w];
7972  SCIP_CALL( delCoefPos(scip, cons, w) );
7973  }
7974  assert(w == splitpos);
7975 
7976  ++(*nchgsides);
7977  *nchgcoefs += (nvars - splitpos);
7978 
7979  /* division by greatest common divisor */
7980  gcd = weights[w];
7981  for( ; w >= 0 && gcd > 1; --w )
7982  {
7983  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7984  }
7985 
7986  /* normalize if possible */
7987  if( gcd > 1 )
7988  {
7989  for( w = splitpos; w >= 0; --w )
7990  {
7991  consdataChgWeight(consdata, w, weights[w]/gcd);
7992  }
7993  (*nchgcoefs) += nvars;
7994 
7995  consdata->capacity /= gcd;
7996  ++(*nchgsides);
7997  }
7998 
7999  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8000  * weight must not be sorted by their index
8001  */
8002 #ifndef NDEBUG
8003  for( w = consdata->nvars - 1; w > 0; --w )
8004  assert(weights[w] <= weights[w - 1]);
8005 #endif
8006  }
8007  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8008  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8009  * splitpos and needs to fit into the knapsack
8010  */
8011  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8012  {
8013  int* clqpart;
8014  int nclq;
8015  int len;
8016 
8017  len = nvars - (splitpos + 1);
8018  /* allocate temporary memory */
8019  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8020 
8021  /* calculate clique partition */
8022  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8023 
8024  /* check if we found at least one clique */
8025  if( nclq < len )
8026  {
8027  SCIP_Longint maxactduetoclq;
8028  int cliquenum;
8029 
8030  maxactduetoclq = 0;
8031  cliquenum = 0;
8032 
8033  /* calculate maximum activity due to cliques */
8034  for( w = 0; w < len; ++w )
8035  {
8036  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8037  if( clqpart[w] == cliquenum )
8038  {
8039  maxactduetoclq += weights[w + splitpos + 1];
8040  ++cliquenum;
8041  }
8042  }
8043 
8044  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8045  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8046  */
8047  if( frontsum + maxactduetoclq <= capacity )
8048  {
8049  SCIP_VAR** clqvars;
8050  int nclqvars;
8051  int c;
8052 
8053  assert(maxactduetoclq < weights[splitpos]);
8054 
8055  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8056 
8057  /* allocate temporary memory */
8058  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8059 
8060  for( c = 0; c < nclq; ++c )
8061  {
8062  nclqvars = 0;
8063  for( w = 0; w < len; ++w )
8064  {
8065  if( clqpart[w] == c )
8066  {
8067  clqvars[nclqvars] = vars[w + splitpos + 1];
8068  ++nclqvars;
8069  }
8070  }
8071 
8072  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8073  if( nclqvars > 1 )
8074  {
8075  SCIP_CONS* cliquecons;
8076  char name[SCIP_MAXSTRLEN];
8077 
8078  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8079  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8083  SCIPconsIsStickingAtNode(cons)) );
8084  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8085  SCIPdebugPrintCons(scip, cliquecons, NULL);
8086  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8087  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8088  ++(*naddconss);
8089  }
8090  }
8091 
8092  /* delete items and update capacity */
8093  for( w = nvars - 1; w > splitpos; --w )
8094  {
8095  SCIP_CALL( delCoefPos(scip, cons, w) );
8096  ++(*nchgcoefs);
8097  }
8098  consdata->capacity -= maxactduetoclq;
8099  assert(frontsum <= consdata->capacity);
8100  ++(*nchgsides);
8101 
8102  assert(w == splitpos);
8103 
8104  /* renew weights pointer */
8105  weights = consdata->weights;
8106 
8107  /* division by greatest common divisor */
8108  gcd = weights[w];
8109  for( ; w >= 0 && gcd > 1; --w )
8110  {
8111  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8112  }
8113 
8114  /* normalize if possible */
8115  if( gcd > 1 )
8116  {
8117  for( w = splitpos; w >= 0; --w )
8118  {
8119  consdataChgWeight(consdata, w, weights[w]/gcd);
8120  }
8121  (*nchgcoefs) += nvars;
8122 
8123  consdata->capacity /= gcd;
8124  ++(*nchgsides);
8125  }
8126 
8127  /* free temporary memory */
8128  SCIPfreeBufferArray(scip, &clqvars);
8129 
8130  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8131  * weight must not be sorted by their index
8132  */
8133 #ifndef NDEBUG
8134  for( w = consdata->nvars - 1; w > 0; --w )
8135  assert(weights[w] <= weights[w - 1]);
8136 #endif
8137  }
8138  }
8139 
8140  /* free temporary memory */
8141  SCIPfreeBufferArray(scip, &clqpart);
8142  }
8143 
8144  return SCIP_OKAY;
8145 }
8146 
8147 /* detect redundant variables which always fits into the knapsack
8148  *
8149  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8150  *
8151  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8152  * => x4, x5 always fits into the knapsack, so we can delete them
8153  *
8154  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8155  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8156  */
8157 static
8159  SCIP* scip, /**< SCIP data structure */
8160  SCIP_CONS* cons, /**< knapsack constraint */
8161  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8162  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8163  int* nchgsides, /**< pointer to store the amount of changed sides */
8164  int* naddconss /**< pointer to count number of added constraints */
8165  )
8167  SCIP_CONSHDLRDATA* conshdlrdata;
8168  SCIP_CONSDATA* consdata;
8169  SCIP_VAR** vars;
8170  SCIP_Longint* weights;
8171  SCIP_Longint capacity;
8172  SCIP_Longint sum;
8173  int noldchgcoefs;
8174  int nvars;
8175  int v;
8176  int w;
8177 
8178  assert(scip != NULL);
8179  assert(cons != NULL);
8180  assert(ndelconss != NULL);
8181  assert(nchgcoefs != NULL);
8182  assert(nchgsides != NULL);
8183  assert(naddconss != NULL);
8184 
8185  consdata = SCIPconsGetData(cons);
8186  assert(consdata != NULL);
8187  assert(consdata->nvars >= 2);
8188  assert(consdata->weightsum > consdata->capacity);
8189 
8190  noldchgcoefs = *nchgcoefs;
8191  vars = consdata->vars;
8192  weights = consdata->weights;
8193  nvars = consdata->nvars;
8194  capacity = consdata->capacity;
8195  sum = 0;
8196 
8197  /* search for maximal fitting items */
8198  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8199  sum += weights[v];
8200 
8201  assert(v < nvars);
8202 
8203  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8204  if( v == nvars - 1 )
8205  {
8206  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8207  assert(SCIPconsIsDeleted(cons));
8208 
8209  return SCIP_OKAY;
8210  }
8211 
8212  if( v < nvars - 1 )
8213  {
8214  /* try to delete variables */
8215  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8216  assert(consdata->nvars > 1);
8217 
8218  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8219  if( v == consdata->nvars - 1 )
8220  {
8221  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8222  assert(SCIPconsIsDeleted(cons));
8223  }
8224 
8225  return SCIP_OKAY;
8226  }
8227 
8228  /* if we already found some redundant variables, stop here */
8229  if( *nchgcoefs > noldchgcoefs )
8230  return SCIP_OKAY;
8231 
8232  assert(vars == consdata->vars);
8233  assert(weights == consdata->weights);
8234  assert(nvars == consdata->nvars);
8235  assert(capacity == consdata->capacity);
8236 
8237  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8238  assert(conshdlrdata != NULL);
8239  /* calculate clique partition */
8240  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8241 
8242  /* check for real existing cliques */
8243  if( consdata->cliquepartition[v] < v )
8244  {
8245  SCIP_Longint sumfront;
8246  SCIP_Longint maxactduetoclqfront;
8247  int* clqpart;
8248  int cliquenum;
8249 
8250  sumfront = 0;
8251  maxactduetoclqfront = 0;
8252 
8253  clqpart = consdata->cliquepartition;
8254  cliquenum = 0;
8255 
8256  /* calculate maximal activity due to cliques */
8257  for( w = 0; w < nvars; ++w )
8258  {
8259  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8260  if( clqpart[w] == cliquenum )
8261  {
8262  if( maxactduetoclqfront + weights[w] <= capacity )
8263  {
8264  maxactduetoclqfront += weights[w];
8265  ++cliquenum;
8266  }
8267  else
8268  break;
8269  }
8270  sumfront += weights[w];
8271  }
8272  assert(w >= v);
8273 
8274  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8275  * information
8276  */
8277  if( conshdlrdata->disaggregation && w == nvars )
8278  {
8279  SCIP_VAR** clqvars;
8280  int nclqvars;
8281  int c;
8282  int ncliques;
8283 
8284  assert(maxactduetoclqfront <= capacity);
8285 
8286  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8287 
8288  ncliques = consdata->ncliques;
8289 
8290  /* allocate temporary memory */
8291  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8292 
8293  for( c = 0; c < ncliques; ++c )
8294  {
8295  nclqvars = 0;
8296  for( w = 0; w < nvars; ++w )
8297  {
8298  if( clqpart[w] == c )
8299  {
8300  clqvars[nclqvars] = vars[w];
8301  ++nclqvars;
8302  }
8303  }
8304 
8305  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8306  if( nclqvars > 1 )
8307  {
8308  SCIP_CONS* cliquecons;
8309  char name[SCIP_MAXSTRLEN];
8310 
8311  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8312  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8316  SCIPconsIsStickingAtNode(cons)) );
8317  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8318  SCIPdebugPrintCons(scip, cliquecons, NULL);
8319  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8320  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8321  ++(*naddconss);
8322  }
8323  }
8324 
8325  /* delete old constraint */
8326  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8327  ++(*ndelconss);
8328 
8329  SCIPfreeBufferArray(scip, &clqvars);
8330 
8331  return SCIP_OKAY;
8332  }
8333 
8334  if( w > v && w < nvars - 1 )
8335  {
8336  /* try to delete variables */
8337  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8338  }
8339  }
8340 
8341  return SCIP_OKAY;
8342 }
8343 
8344 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8345 static
8346 void normalizeWeights(
8347  SCIP_CONS* cons, /**< knapsack constraint */
8348  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8349  int* nchgsides /**< pointer to count number of side changes */
8350  )
8351 {
8352  SCIP_CONSDATA* consdata;
8353  SCIP_Longint gcd;
8354  int i;
8355 
8356  assert(nchgcoefs != NULL);
8357  assert(nchgsides != NULL);
8358  assert(!SCIPconsIsModifiable(cons));
8359 
8360  consdata = SCIPconsGetData(cons);
8361  assert(consdata != NULL);
8362  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8363  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8364  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8365  assert(consdata->nvars >= 1);
8366 
8367  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8368  sortItems(consdata);
8369 
8370  gcd = consdata->weights[consdata->nvars-1];
8371  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8372  {
8373  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8374  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8375 
8376  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8377  }
8378 
8379  if( gcd >= 2 )
8380  {
8381  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8382 
8383  for( i = 0; i < consdata->nvars; ++i )
8384  {
8385  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8386  }
8387  consdata->capacity /= gcd;
8388  (*nchgcoefs) += consdata->nvars;
8389  (*nchgsides)++;
8390 
8391  /* weight should still be sorted, because the reduction preserves this */
8392 #ifndef NDEBUG
8393  for( i = consdata->nvars - 1; i > 0; --i )
8394  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8395 #endif
8396  consdata->sorted = TRUE;
8397  }
8398 }
8399 
8400 /** dual weights tightening for knapsack constraints
8401  *
8402  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8403  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8404  * constraint
8405  *
8406  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8407  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8408  *
8409  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8410  *
8411  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8412  *
8413  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8414  *
8415  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8416  *
8417  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8418  */
8419 static
8421  SCIP* scip, /**< SCIP data structure */
8422  SCIP_CONS* cons, /**< knapsack constraint */
8423  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8424  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8425  int* nchgsides, /**< pointer to store the amount of changed sides */
8426  int* naddconss /**< pointer to count number of added constraints */
8427  )
8429  SCIP_CONSDATA* consdata;
8430  SCIP_Longint* weights;
8431  SCIP_Longint dualcapacity;
8432  SCIP_Longint reductionsum;
8433  SCIP_Longint capacity;
8434  SCIP_Longint exceedsum;
8435  int oldnchgcoefs;
8436  int nvars;
8437  int vbig;
8438  int v;
8439  int w;
8440 #ifndef NDEBUG
8441  int oldnchgsides;
8442 #endif
8443 
8444  assert(scip != NULL);
8445  assert(cons != NULL);
8446  assert(ndelconss != NULL);
8447  assert(nchgcoefs != NULL);
8448  assert(nchgsides != NULL);
8449  assert(naddconss != NULL);
8450 
8451 #ifndef NDEBUG
8452  oldnchgsides = *nchgsides;
8453 #endif
8454 
8455  consdata = SCIPconsGetData(cons);
8456  assert(consdata != NULL);
8457  assert(consdata->weightsum > consdata->capacity);
8458  assert(consdata->nvars >= 2);
8459  assert(consdata->sorted);
8460 
8461  /* constraint should be merged */
8462  assert(consdata->merged);
8463 
8464  nvars = consdata->nvars;
8465  weights = consdata->weights;
8466  capacity = consdata->capacity;
8467 
8468  oldnchgcoefs = *nchgcoefs;
8469 
8470  /* case 1. */
8471  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8472  {
8473  SCIP_CONS* newcons;
8474 
8475  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8476  *
8477  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8478  */
8479  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8480 
8481  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8485  SCIPconsIsStickingAtNode(cons)) );
8486 
8487  SCIP_CALL( SCIPaddCons(scip, newcons) );
8488  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8489  ++(*naddconss);
8490 
8491  SCIP_CALL( SCIPdelCons(scip, cons) );
8492  ++(*ndelconss);
8493 
8494  return SCIP_OKAY;
8495  }
8496 
8497  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8498  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8499  {
8500  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8501  assert(SCIPconsIsDeleted(cons));
8502 
8503  return SCIP_OKAY;
8504  }
8505 
8506  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8507  /* @todo might be changed/removed when improving the coeffcients tightening */
8508  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8509  return SCIP_OKAY;
8510 
8511  /* case 2. */
8512 
8513  v = 0;
8514 
8515  /* @todo generalize the following algorithm for several parts of the knapsack
8516  *
8517  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8518  * variables each combination is a minimal cover, some examples
8519  *
8520  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8521  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8522  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8523  *
8524  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8525  *
8526  */
8527 
8528  /* determine big weights that fit only by itself */
8529  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8530  ++v;
8531 
8532  vbig = v;
8533  assert(vbig < nvars - 1);
8534  exceedsum = 0;
8535 
8536  /* determine the amount needed to exceed the capacity */
8537  while( v < nvars && exceedsum <= capacity )
8538  {
8539  exceedsum += weights[v];
8540  ++v;
8541  }
8542 
8543  /* if we exceeded the capacity we might reduce the weights */
8544  if( exceedsum > capacity )
8545  {
8546  assert(vbig > 0 || v < nvars);
8547 
8548  /* all small weights were needed to exceed the capacity */
8549  if( v == nvars )
8550  {
8551  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8552  assert(newweight > 0);
8553 
8554  /* reduce big weights */
8555  for( v = 0; v < vbig; ++v )
8556  {
8557  if( weights[v] > newweight )
8558  {
8559  consdataChgWeight(consdata, v, newweight);
8560  ++(*nchgcoefs);
8561  }
8562  }
8563 
8564  /* reduce small weights */
8565  for( ; v < nvars; ++v )
8566  {
8567  if( weights[v] > 1 )
8568  {
8569  consdataChgWeight(consdata, v, 1LL);
8570  ++(*nchgcoefs);
8571  }
8572  }
8573 
8574  consdata->capacity = newweight;
8575 
8576  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8577  * weight must not be sorted by their index
8578  */
8579 #ifndef NDEBUG
8580  for( v = nvars - 1; v > 0; --v )
8581  assert(weights[v] <= weights[v-1]);
8582 #endif
8583 
8584  return SCIP_OKAY;
8585  }
8586  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8587  * small weights
8588  */
8589  else
8590  {
8591  SCIP_Longint exceedsumback = 0;
8592  int nexceed = v - vbig;
8593 
8594  assert(nexceed > 1);
8595 
8596  /* determine weightsum of the same amount as before but of the smallest weight */
8597  for( w = nvars - 1; w >= nvars - nexceed; --w )
8598  exceedsumback += weights[w];
8599 
8600  assert(w >= 0);
8601 
8602  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8603  * combinations of all small weights
8604  */
8605  if( exceedsumback > capacity )
8606  {
8607  SCIP_Longint newweight = nexceed - 1;
8608 
8609  /* taking out the smallest element needs to fit */
8610  assert(exceedsumback - weights[nvars - 1] <= capacity);
8611 
8612  /* reduce big weights */
8613  for( v = 0; v < vbig; ++v )
8614  {
8615  if( weights[v] > newweight )
8616  {
8617  consdataChgWeight(consdata, v, newweight);
8618  ++(*nchgcoefs);
8619  }
8620  }
8621 
8622  /* reduce small weights */
8623  for( ; v < nvars; ++v )
8624  {
8625  if( weights[v] > 1 )
8626  {
8627  consdataChgWeight(consdata, v, 1LL);
8628  ++(*nchgcoefs);
8629  }
8630  }
8631 
8632  consdata->capacity = newweight;
8633 
8634  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8635  * weight must not be sorted by their index
8636  */
8637 #ifndef NDEBUG
8638  for( v = nvars - 1; v > 0; --v )
8639  assert(weights[v] <= weights[v-1]);
8640 #endif
8641  return SCIP_OKAY;
8642  }
8643  }
8644  }
8645  else
8646  {
8647  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8648  * not happen here
8649  */
8650  assert(vbig > 0 && vbig < nvars);
8651 
8652  /* either choose a big coefficients or all other variables
8653  *
8654  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8655  *
8656  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8657  * constraint to
8658  *
8659  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8660  */
8661 
8662  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8663  {
8664  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8665 #ifndef NDEBUG
8666  SCIP_Longint resweightsum = consdata->weightsum;
8667 
8668  for( v = 0; v < vbig; ++v )
8669  resweightsum -= weights[v];
8670 
8671  assert(exceedsum == resweightsum);
8672 #endif
8673  assert(newweight > 0);
8674 
8675  /* reduce big weights */
8676  for( v = 0; v < vbig; ++v )
8677  {
8678  if( weights[v] > newweight )
8679  {
8680  consdataChgWeight(consdata, v, newweight);
8681  ++(*nchgcoefs);
8682  }
8683  }
8684 
8685  /* reduce small weights */
8686  for( ; v < nvars; ++v )
8687  {
8688  if( weights[v] > 1 )
8689  {
8690  consdataChgWeight(consdata, v, 1LL);
8691  ++(*nchgcoefs);
8692  }
8693  }
8694 
8695  consdata->capacity = newweight;
8696 
8697  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8698  * weight must not be sorted by their index
8699  */
8700 #ifndef NDEBUG
8701  for( v = nvars - 1; v > 0; --v )
8702  assert(weights[v] <= weights[v-1]);
8703 #endif
8704  return SCIP_OKAY;
8705  }
8706  }
8707 
8708  /* case 3. */
8709 
8710  dualcapacity = consdata->weightsum - capacity;
8711  reductionsum = 0;
8712  v = 0;
8713 
8714  /* reduce big weights
8715  *
8716  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8717  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8718  * <=> x0 + x1 + x2 + x3 <= 3
8719  */
8720  while( weights[v] > dualcapacity )
8721  {
8722  reductionsum += (weights[v] - dualcapacity);
8723  consdataChgWeight(consdata, v, dualcapacity);
8724  ++v;
8725  assert(v < nvars);
8726  }
8727  (*nchgcoefs) += v;
8728 
8729  /* skip weights equal to the dualcapacity, because we cannot change them */
8730  while( v < nvars && weights[v] == dualcapacity )
8731  ++v;
8732 
8733  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8734  * after a possible removal of the last, redundant item
8735  *
8736  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8737  */
8738  if( v >= nvars - 1 )
8739  {
8740  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8741  if( v == nvars - 1 )
8742  {
8743  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8744  }
8745  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8746  assert(SCIPconsIsDeleted(cons));
8747 
8748  return SCIP_OKAY;
8749  }
8750  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8751  {
8752  /* @todo generalize the following algorithm for more than two variables */
8753 
8754  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8755  {
8756  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8757  * coefficients) of all or two variables of the rest
8758  *
8759  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8760  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8761  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8762  *
8763  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8764  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8765  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8766  *
8767  */
8768  if( v > 0 && weights[nvars - 2] > 1 )
8769  {
8770  int ncoefchg = 0;
8771 
8772  /* reduce all bigger weights */
8773  for( w = 0; w < v; ++w )
8774  {
8775  if( weights[w] > 2 )
8776  {
8777  consdataChgWeight(consdata, w, 2LL);
8778  ++ncoefchg;
8779  }
8780  else
8781  {
8782  assert(weights[0] == 2);
8783  assert(weights[v - 1] == 2);
8784  break;
8785  }
8786  }
8787 
8788  /* reduce all smaller weights */
8789  for( w = v; w < nvars; ++w )
8790  {
8791  if( weights[w] > 1 )
8792  {
8793  consdataChgWeight(consdata, w, 1LL);
8794  ++ncoefchg;
8795  }
8796  }
8797  assert(ncoefchg > 0);
8798 
8799  (*nchgcoefs) += ncoefchg;
8800 
8801  /* correct the capacity */
8802  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8803  assert(consdata->capacity > 0);
8804  assert(weights[0] <= consdata->capacity);
8805  assert(consdata->weightsum > consdata->capacity);
8806  /* reset the reductionsum */
8807  reductionsum = 0;
8808  }
8809  else if( v == 0 )
8810  {
8811  assert(weights[nvars - 2] == 1);
8812  }
8813  }
8814  else
8815  {
8816  SCIP_Longint minweight = weights[nvars - 1];
8817  SCIP_Longint newweight = dualcapacity - minweight;
8818  SCIP_Longint restsumweights = 0;
8819  SCIP_Longint sumcoef;
8820  SCIP_Bool sumcoefcase = FALSE;
8821  int startv = v;
8822  int end;
8823  int k;
8824 
8825  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8826 
8827  /* reduce big weights of pairs that exceed the dualcapacity
8828  *
8829  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8830  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8831  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8832  */
8833  while( weights[v] > newweight )
8834  {
8835  reductionsum += (weights[v] - newweight);
8836  consdataChgWeight(consdata, v, newweight);
8837  ++v;
8838  assert(v < nvars);
8839  }
8840  (*nchgcoefs) += (v - startv);
8841 
8842  /* skip equal weights */
8843  while( weights[v] == newweight )
8844  ++v;
8845 
8846  if( v > 0 )
8847  {
8848  for( w = v; w < nvars; ++w )
8849  restsumweights += weights[w];
8850  }
8851  else
8852  restsumweights = consdata->weightsum;
8853 
8854  if( restsumweights < dualcapacity )
8855  {
8856  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8857  *
8858  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8859  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8860  */
8861  if( startv == v )
8862  {
8863  /* remove redundant variables */
8864  for( w = nvars - 1; w >= v; --w )
8865  {
8866  SCIP_CALL( delCoefPos(scip, cons, v) );
8867  ++(*nchgcoefs);
8868  }
8869 
8870 #ifndef NDEBUG
8871  /* each coefficients should exceed the dualcapacity by itself */
8872  for( ; w >= 0; --w )
8873  assert(weights[w] == dualcapacity);
8874 #endif
8875  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8876  * upgrade this constraint
8877  */
8878  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8879  assert(SCIPconsIsDeleted(cons));
8880 
8881  return SCIP_OKAY;
8882  }
8883 
8884  /* special case where we have three different coefficient types
8885  *
8886  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8887  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8888  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8889  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8890  */
8891  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8892  {
8893  SCIP_Longint newcap;
8894 
8895  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8896  for( w = nvars - 1; w >= v; --w )
8897  {
8898  if( weights[w] > 1 )
8899  {
8900  consdataChgWeight(consdata, w, 1LL);
8901  ++(*nchgcoefs);
8902  }
8903  }
8904 
8905  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8906  * dualcapacity
8907  */
8908  newweight = (SCIP_Longint)nvars - v;
8909  assert(newweight > 1);
8910  for( ; w >= startv; --w )
8911  {
8912  if( weights[w] > newweight )
8913  {
8914  consdataChgWeight(consdata, w, newweight);
8915  ++(*nchgcoefs);
8916  }
8917  else
8918  assert(weights[w] == newweight);
8919  }
8920 
8921  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8922  ++newweight;
8923  assert(newweight > 2);
8924  for( ; w >= 0; --w )
8925  {
8926  if( weights[w] > newweight )
8927  {
8928  consdataChgWeight(consdata, w, newweight);
8929  ++(*nchgcoefs);
8930  }
8931  else
8932  assert(weights[w] == newweight);
8933  }
8934 
8935  /* update the capacity */
8936  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8937  if( consdata->capacity > newcap )
8938  {
8939  consdata->capacity = newcap;
8940  ++(*nchgsides);
8941  }
8942  else
8943  assert(consdata->capacity == newcap);
8944  }
8945  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8946 
8947  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8948  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8949 
8950  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8951  * weight must not be sorted by their index
8952  */
8953 #ifndef NDEBUG
8954  for( w = nvars - 1; w > 0; --w )
8955  assert(weights[w] <= weights[w - 1]);
8956 #endif
8957  return SCIP_OKAY;
8958  }
8959 
8960  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8961  end = nvars - 2;
8962  while( end >= 0 && weights[end] == weights[end + 1] )
8963  {
8964  assert(end >= v);
8965  --end;
8966  }
8967 
8968  if( v >= end )
8969  goto TERMINATE;
8970 
8971  end = nvars - 2;
8972 
8973  /* can we stop early, another special reduction case might exist */
8974  if( 2 * weights[end] > dualcapacity )
8975  {
8976  restsumweights = 0;
8977 
8978  /* determine capacity of the small items */
8979  for( w = end + 1; w < nvars; ++w )
8980  restsumweights += weights[w];
8981 
8982  if( restsumweights * 2 <= dualcapacity )
8983  {
8984  /* check for further posssible reductions in the middle */
8985  while( v < end && restsumweights + weights[v] >= dualcapacity )
8986  ++v;
8987 
8988  if( v >= end )
8989  goto TERMINATE;
8990 
8991  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8992  if( (dualcapacity & 1) == 0 )
8993  {
8994  newweight = dualcapacity / 2;
8995 
8996  /* set all middle coefficients */
8997  for( ; v <= end; ++v )
8998  {
8999  if( weights[v] > newweight )
9000  {
9001  reductionsum += (weights[v] - newweight);
9002  consdataChgWeight(consdata, v, newweight);
9003  ++(*nchgcoefs);
9004  }
9005  }
9006  }
9007  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9008  * other coefficients by 2
9009  */
9010  else
9011  {
9012  /* correct the reductionsum */
9013  reductionsum *= 2;
9014 
9015  /* multiply big coefficients by 2 */
9016  for( w = 0; w < v; ++w )
9017  {
9018  consdataChgWeight(consdata, w, weights[w] * 2);
9019  }
9020 
9021  newweight = dualcapacity;
9022  /* set all middle coefficients */
9023  for( ; v <= end; ++v )
9024  {
9025  reductionsum += (2 * weights[v] - newweight);
9026  consdataChgWeight(consdata, v, newweight);
9027  }
9028 
9029  /* multiply small coefficients by 2 */
9030  for( w = end + 1; w < nvars; ++w )
9031  {
9032  consdataChgWeight(consdata, w, weights[w] * 2);
9033  }
9034  (*nchgcoefs) += nvars;
9035 
9036  dualcapacity *= 2;
9037  consdata->capacity *= 2;
9038  ++(*nchgsides);
9039  }
9040  }
9041 
9042  goto TERMINATE;
9043  }
9044 
9045  /* further reductions using the next possible coefficient sum
9046  *
9047  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9048  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9049  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9050  */
9051  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9052  for( k = 0; k < 4; ++k )
9053  {
9054  /* determine next minimal coefficient sum */
9055  switch( k )
9056  {
9057  case 0:
9058  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9059  break;
9060  case 1:
9061  assert(nvars >= 3);
9062  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9063  break;
9064  case 2:
9065  assert(nvars >= 4);
9066  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9067  {
9068  sumcoefcase = TRUE;
9069  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9070  }
9071  else
9072  {
9073  sumcoefcase = FALSE;
9074  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9075  }
9076  break;
9077  case 3:
9078  assert(nvars >= 5);
9079  if( sumcoefcase )
9080  {
9081  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9082  }
9083  else
9084  {
9085  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9086  }
9087  break;
9088  default:
9089  return SCIP_ERROR;
9090  }
9091 
9092  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9093  minweight = weights[end];
9094  while( minweight <= sumcoef )
9095  {
9096  newweight = dualcapacity - minweight;
9097  startv = v;
9098  assert(v < nvars);
9099 
9100  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9101  /* shrink big coefficients */
9102  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9103  {
9104  reductionsum += (weights[v] - newweight);
9105  consdataChgWeight(consdata, v, newweight);
9106  ++v;
9107  assert(v < nvars);
9108  }
9109  (*nchgcoefs) += (v - startv);
9110 
9111  /* skip unchangable weights */
9112  while( weights[v] + minweight == dualcapacity )
9113  {
9114  assert(v < nvars);
9115  ++v;
9116  }
9117 
9118  --end;
9119  /* skip same end weights */
9120  while( end >= 0 && weights[end] == weights[end + 1] )
9121  --end;
9122 
9123  if( v >= end )
9124  goto TERMINATE;
9125 
9126  minweight = weights[end];
9127  }
9128 
9129  if( v >= end )
9130  goto TERMINATE;
9131 
9132  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9133  if( sumcoef < minweight )
9134  {
9135  minweight = sumcoef;
9136  newweight = dualcapacity - minweight;
9137  startv = v;
9138  assert(v < nvars);
9139 
9140  /* shrink big coefficients */
9141  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9142  {
9143  reductionsum += (weights[v] - newweight);
9144  consdataChgWeight(consdata, v, newweight);
9145  ++v;
9146  assert(v < nvars);
9147  }
9148  (*nchgcoefs) += (v - startv);
9149 
9150  /* skip unchangable weights */
9151  while( weights[v] + minweight == dualcapacity )
9152  {
9153  assert(v < nvars);
9154  ++v;
9155  }
9156  }
9157 
9158  if( v >= end )
9159  goto TERMINATE;
9160 
9161  /* can we stop early, another special reduction case might exist */
9162  if( 2 * weights[end] > dualcapacity )
9163  {
9164  restsumweights = 0;
9165 
9166  /* determine capacity of the small items */
9167  for( w = end + 1; w < nvars; ++w )
9168  restsumweights += weights[w];
9169 
9170  if( restsumweights * 2 <= dualcapacity )
9171  {
9172  /* check for further posssible reductions in the middle */
9173  while( v < end && restsumweights + weights[v] >= dualcapacity )
9174  ++v;
9175 
9176  if( v >= end )
9177  goto TERMINATE;
9178 
9179  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9180  if( (dualcapacity & 1) == 0 )
9181  {
9182  newweight = dualcapacity / 2;
9183 
9184  /* set all middle coefficients */
9185  for( ; v <= end; ++v )
9186  {
9187  if( weights[v] > newweight )
9188  {
9189  reductionsum += (weights[v] - newweight);
9190  consdataChgWeight(consdata, v, newweight);
9191  ++(*nchgcoefs);
9192  }
9193  }
9194  }
9195  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9196  * other coefficients by 2
9197  */
9198  else
9199  {
9200  /* correct the reductionsum */
9201  reductionsum *= 2;
9202 
9203  /* multiply big coefficients by 2 */
9204  for( w = 0; w < v; ++w )
9205  {
9206  consdataChgWeight(consdata, w, weights[w] * 2);
9207  }
9208 
9209  newweight = dualcapacity;
9210  /* set all middle coefficients */
9211  for( ; v <= end; ++v )
9212  {
9213  reductionsum += (2 * weights[v] - newweight);
9214  consdataChgWeight(consdata, v, newweight);
9215  }
9216 
9217  /* multiply small coefficients by 2 */
9218  for( w = end + 1; w < nvars; ++w )
9219  {
9220  consdataChgWeight(consdata, w, weights[w] * 2);
9221  }
9222  (*nchgcoefs) += nvars;
9223 
9224  dualcapacity *= 2;
9225  consdata->capacity *= 2;
9226  ++(*nchgsides);
9227  }
9228  }
9229 
9230  goto TERMINATE;
9231  }
9232 
9233  /* cannot tighten any further */
9234  if( 2 * sumcoef > dualcapacity )
9235  goto TERMINATE;
9236  }
9237  }
9238  }
9239 
9240  TERMINATE:
9241  /* correct capacity */
9242  if( reductionsum > 0 )
9243  {
9244  assert(v > 0);
9245 
9246  consdata->capacity -= reductionsum;
9247  ++(*nchgsides);
9248 
9249  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9250  }
9251  assert(weights[0] <= consdata->capacity);
9252 
9253  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9254  * weight must not be sorted by their index
9255  */
9256 #ifndef NDEBUG
9257  for( w = nvars - 1; w > 0; --w )
9258  assert(weights[w] <= weights[w - 1]);
9259 #endif
9260 
9261  if( oldnchgcoefs < *nchgcoefs )
9262  {
9263  assert(!SCIPconsIsDeleted(cons));
9264 
9265  /* it might be that we can divide the weights by their greatest common divisor */
9266  normalizeWeights(cons, nchgcoefs, nchgsides);
9267  }
9268  else
9269  {
9270  assert(oldnchgcoefs == *nchgcoefs);
9271  assert(oldnchgsides == *nchgsides);
9272  }
9273 
9274  return SCIP_OKAY;
9275 }
9276 
9277 
9278 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9279 static
9281  SCIP* scip, /**< SCIP data structure */
9282  SCIP_CONS* cons, /**< knapsack constraint */
9283  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9284  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9285  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9286  )
9287 {
9288  SCIP_VAR** vars;
9289  SCIP_CONSDATA* consdata;
9290  SCIP_Longint* weights;
9291  SCIP_Longint capacity;
9292  SCIP_Bool infeasible;
9293  SCIP_Bool fixed;
9294  int nvars;
9295  int v;
9296 
9297  assert(scip != NULL);
9298  assert(cons != NULL);
9299  assert(nfixedvars != NULL);
9300  assert(ndelconss != NULL);
9301  assert(nchgcoefs != NULL);
9302 
9303  consdata = SCIPconsGetData(cons);
9304  assert(consdata != NULL);
9305 
9306  nvars = consdata->nvars;
9307 
9308  /* no variables left, then delete constraint */
9309  if( nvars == 0 )
9310  {
9311  assert(consdata->capacity >= 0);
9312 
9313  SCIP_CALL( SCIPdelCons(scip, cons) );
9314  ++(*ndelconss);
9315 
9316  return SCIP_OKAY;
9317  }
9318 
9319  /* sort items */
9320  sortItems(consdata);
9321 
9322  vars = consdata->vars;
9323  weights = consdata->weights;
9324  capacity = consdata->capacity;
9325  v = 0;
9326 
9327  /* check for weights bigger than the capacity */
9328  while( v < nvars && weights[v] > capacity )
9329  {
9330  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9331  assert(!infeasible);
9332 
9333  if( fixed )
9334  ++(*nfixedvars);
9335 
9336  ++v;
9337  }
9338 
9339  /* if we fixed at least one variable we need to delete them from the constraint */
9340  if( v > 0 )
9341  {
9342  if( v == nvars )
9343  {
9344  SCIP_CALL( SCIPdelCons(scip, cons) );
9345  ++(*ndelconss);
9346 
9347  return SCIP_OKAY;
9348  }
9349 
9350  /* delete all position from back to front */
9351  for( --v; v >= 0; --v )
9352  {
9353  SCIP_CALL( delCoefPos(scip, cons, v) );
9354  ++(*nchgcoefs);
9355  }
9356 
9357  /* sort items again because of deletion */
9358  sortItems(consdata);
9359  assert(vars == consdata->vars);
9360  assert(weights == consdata->weights);
9361  }
9362  assert(consdata->sorted);
9363  assert(weights[0] <= capacity);
9364 
9365  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9366  {
9367  SCIP_CALL( SCIPdelCons(scip, cons) );
9368  ++(*ndelconss);
9369  }
9370 
9371  return SCIP_OKAY;
9372 }
9373 
9374 
9375 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9376  *
9377  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9378  *
9379  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9380  *
9381  * the above constraint can be changed to
9382  *
9383  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9384  *
9385  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9386  *
9387  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9388  *
9389  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9390  * constraint further, e.g.
9391  *
9392  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9393  * => 2x1 + x2 + x3 + x4 <= 2
9394  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9395  */
9396 static
9398  SCIP* scip, /**< SCIP data structure */
9399  SCIP_CONS* cons, /**< knapsack constraint */
9400  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9401  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9402  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9403  int* nchgsides, /**< pointer to store the amount of changed sides */
9404  int* naddconss, /**< pointer to count number of added constraints */
9405  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9406  )
9407 {
9408  SCIP_VAR** vars;
9409  SCIP_CONSDATA* consdata;
9410  SCIP_Longint* weights;
9411  SCIP_Longint restweight;
9412  SCIP_Longint newweight;
9413  SCIP_Longint weight;
9414  SCIP_Longint oldgcd;
9415  SCIP_Longint rest;
9416  SCIP_Longint gcd;
9417  int oldnchgcoefs;
9418  int oldnchgsides;
9419  int candpos;
9420  int candpos2;
9421  int offsetv;
9422  int nvars;
9423  int v;
9424 
9425  assert(scip != NULL);
9426  assert(cons != NULL);
9427  assert(nfixedvars != NULL);
9428  assert(ndelconss != NULL);
9429  assert(nchgcoefs != NULL);
9430  assert(nchgsides != NULL);
9431  assert(naddconss != NULL);
9432  assert(cutoff != NULL);
9433  assert(!SCIPconsIsModifiable(cons));
9434 
9435  consdata = SCIPconsGetData(cons);
9436  assert( consdata != NULL );
9437 
9438  *cutoff = FALSE;
9439 
9440  /* remove double enties and also combinations of active and negated variables */
9441  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9442  assert(consdata->merged);
9443  if( *cutoff )
9444  return SCIP_OKAY;
9445 
9446  assert(consdata->capacity >= 0);
9447 
9448  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9449  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9450 
9451  if( SCIPconsIsDeleted(cons) )
9452  return SCIP_OKAY;
9453 
9454  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9455  {
9456  /* 1. dual weights tightening */
9457  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9458 
9459  if( SCIPconsIsDeleted(cons) )
9460  return SCIP_OKAY;
9461  /* 2. delete redundant variables */
9462  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9463 
9464  if( SCIPconsIsDeleted(cons) )
9465  return SCIP_OKAY;
9466  }
9467 
9468  weights = consdata->weights;
9469  nvars = consdata->nvars;
9470 
9471 #ifndef NDEBUG
9472  /* constraint might not be sorted, but the weights are already sorted */
9473  for( v = nvars - 1; v > 0; --v )
9474  assert(weights[v] <= weights[v-1]);
9475 #endif
9476 
9477  /* determine greatest common divisor */
9478  gcd = weights[nvars - 1];
9479  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9480  {
9481  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9482  }
9483 
9484  /* divide the constraint by their greatest common divisor */
9485  if( gcd >= 2 )
9486  {
9487  for( v = nvars - 1; v >= 0; --v )
9488  {
9489  consdataChgWeight(consdata, v, weights[v]/gcd);
9490  }
9491  (*nchgcoefs) += nvars;
9492 
9493  consdata->capacity /= gcd;
9494  (*nchgsides)++;
9495  }
9496  assert(consdata->nvars == nvars);
9497 
9498  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9499  * must not be sorted by their index
9500  */
9501 #ifndef NDEBUG
9502  for( v = nvars - 1; v > 0; --v )
9503  assert(weights[v] <= weights[v-1]);
9504 #endif
9505 
9506  /* 3. start gcd procedure for all variables */
9507  do
9508  {
9509  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9510  SCIPdebug( oldnchgsides = *nchgsides; )
9511 
9512  vars = consdata->vars;
9513  weights = consdata->weights;
9514  nvars = consdata->nvars;
9515 
9516  /* stop if we have two coefficients which are one in absolute value */
9517  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9518  return SCIP_OKAY;
9519 
9520  v = 0;
9521  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9522  * gcd
9523  */
9524  while( weights[v] == consdata->capacity )
9525  {
9526  ++v;
9527  assert(v < nvars);
9528  }
9529 
9530  /* all but one variable are as big as the capacity, this is handled elsewhere */
9531  if( v == nvars - 1 )
9532  return SCIP_OKAY;
9533 
9534  offsetv = v;
9535 
9536  gcd = -1;
9537  candpos = -1;
9538  candpos2 = -1;
9539 
9540  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9541  * change the coefficient
9542  */
9543  for( v = nvars - 1; v >= offsetv; --v )
9544  {
9545  weight = weights[v];
9546  assert(weight >= 1);
9547 
9548  oldgcd = gcd;
9549 
9550  if( gcd == -1 )
9551  {
9552  gcd = weights[v];
9553  assert(gcd >= 1);
9554  }
9555  else
9556  {
9557  /* calculate greatest common divisor for all variables */
9558  gcd = SCIPcalcGreComDiv(gcd, weight);
9559  }
9560 
9561  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9562  * can terminate
9563  */
9564  if( gcd == 1 )
9565  {
9566  /* found candidate */
9567  if( candpos == -1 )
9568  {
9569  gcd = oldgcd;
9570  candpos = v;
9571 
9572  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9573  if( v == nvars - 2 )
9574  candpos2 = v + 1;
9575  }
9576  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9577  else
9578  {
9579  if( candpos == v + 1 && candpos2 == v + 2 )
9580  {
9581  assert(candpos2 == nvars - 1);
9582 
9583  /* take new candidates */
9584  candpos = candpos2;
9585 
9586  /* recalculate gcd from scratch */
9587  gcd = weights[v+1];
9588  assert(gcd >= 1);
9589 
9590  /* calculate greatest common divisor for variables */
9591  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9592  if( gcd == 1 )
9593  return SCIP_OKAY;
9594  }
9595  else
9596  /* cannot determine a possible coefficient for reduction */
9597  return SCIP_OKAY;
9598  }
9599  }
9600  }
9601  assert(gcd >= 2);
9602 
9603  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9604  * further
9605  */
9606  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9607 
9608  /* determine the remainder of the capacity and the gcd */
9609  rest = consdata->capacity % gcd;
9610  assert(rest >= 0);
9611  assert(rest < gcd);
9612 
9613  if( candpos == -1 )
9614  {
9615  /* we assume that the constraint was normalized */
9616  assert(rest > 0);
9617 
9618  /* replace old with new capacity */
9619  consdata->capacity -= rest;
9620  ++(*nchgsides);
9621 
9622  /* replace old big coefficients with new capacity */
9623  for( v = 0; v < offsetv; ++v )
9624  {
9625  consdataChgWeight(consdata, v, consdata->capacity);
9626  }
9627 
9628  *nchgcoefs += offsetv;
9629  goto CONTINUE;
9630  }
9631 
9632  /* determine the remainder of the coefficient candidate and the gcd */
9633  restweight = weights[candpos] % gcd;
9634  assert(restweight >= 1);
9635  assert(restweight < gcd);
9636 
9637  /* calculate new coefficient */
9638  if( restweight > rest )
9639  newweight = weights[candpos] - restweight + gcd;
9640  else
9641  newweight = weights[candpos] - restweight;
9642 
9643  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9644 
9645  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);
9646 
9647  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9648  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9649  */
9650  if( newweight == 0 && offsetv > 0 )
9651  return SCIP_OKAY;
9652 
9653  if( rest > 0 )
9654  {
9655  /* replace old with new capacity */
9656  consdata->capacity -= rest;
9657  ++(*nchgsides);
9658 
9659  /* replace old big coefficients with new capacity */
9660  for( v = 0; v < offsetv; ++v )
9661  {
9662  consdataChgWeight(consdata, v, consdata->capacity);
9663  }
9664 
9665  *nchgcoefs += offsetv;
9666  }
9667 
9668  if( newweight == 0 )
9669  {
9670  /* delete redundant coefficient */
9671  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9672  assert(consdata->nvars == nvars - 1);
9673  --nvars;
9674  }
9675  else
9676  {
9677  /* replace old with new coefficient */
9678  consdataChgWeight(consdata, candpos, newweight);
9679  }
9680  ++(*nchgcoefs);
9681 
9682  assert(consdata->vars == vars);
9683  assert(consdata->nvars == nvars);
9684  assert(consdata->weights == weights);
9685 
9686  CONTINUE:
9687  /* now constraint can be normalized, dividing it by the gcd */
9688  for( v = nvars - 1; v >= 0; --v )
9689  {
9690  consdataChgWeight(consdata, v, weights[v]/gcd);
9691  }
9692  (*nchgcoefs) += nvars;
9693 
9694  consdata->capacity /= gcd;
9695  ++(*nchgsides);
9696 
9697  SCIPdebugPrintCons(scip, cons, NULL);
9698 
9699  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));
9700  }
9701  while( nvars >= 2 );
9702 
9703  return SCIP_OKAY;
9704 }
9705 
9706 
9707 /** inserts an element into the list of binary zero implications */
9708 static
9710  SCIP* scip, /**< SCIP data structure */
9711  int** liftcands, /**< array of the lifting candidates */
9712  int* nliftcands, /**< number of lifting candidates */
9713  int** firstidxs, /**< array of first zeroitems indices */
9714  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9715  int** zeroitems, /**< pointer to zero items array */
9716  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9717  int* zeroitemssize, /**< pointer to size of zero items array */
9718  int* nzeroitems, /**< pointer to length of zero items array */
9719  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9720  SCIP_Bool value, /**< value v of variable y in implication */
9721  int knapsackidx, /**< index of variable x in knapsack */
9722  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9723  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9724  )
9725 {
9726  int nzeros;
9727 
9728  assert(liftcands != NULL);
9729  assert(liftcands[value] != NULL);
9730  assert(nliftcands != NULL);
9731  assert(firstidxs != NULL);
9732  assert(firstidxs[value] != NULL);
9733  assert(zeroweightsums != NULL);
9734  assert(zeroweightsums[value] != NULL);
9735  assert(zeroitems != NULL);
9736  assert(nextidxs != NULL);
9737  assert(zeroitemssize != NULL);
9738  assert(nzeroitems != NULL);
9739  assert(*nzeroitems <= *zeroitemssize);
9740  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9741  assert(memlimitreached != NULL);
9742 
9743  nzeros = *nzeroitems;
9744 
9745  /* allocate enough memory */
9746  if( nzeros == *zeroitemssize )
9747  {
9748  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9749  * this can be too huge - abort on memory limit
9750  */
9751  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9752  {
9753  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9754  *zeroitemssize);
9755  *memlimitreached = TRUE;
9756  return SCIP_OKAY;
9757  }
9758  *zeroitemssize *= 2;
9759  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9760  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9761  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9762  }
9763  assert(nzeros < *zeroitemssize);
9764 
9765  if( *memlimitreached )
9766  *memlimitreached = FALSE;
9767 
9768  /* insert element */
9769  (*zeroitems)[nzeros] = knapsackidx;
9770  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9771  if( firstidxs[value][probindex] == 0 )
9772  {
9773  liftcands[value][nliftcands[value]] = probindex;
9774  ++nliftcands[value];
9775  }
9776  firstidxs[value][probindex] = nzeros;
9777  ++(*nzeroitems);
9778  zeroweightsums[value][probindex] += knapsackweight;
9779 
9780  return SCIP_OKAY;
9781 }
9782 
9783 #define MAX_CLIQUELENGTH 50
9784 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9785  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9786  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9787  * if cliqueweightsum(xi == v) < capacity:
9788  * - fixing variable xi to v would make the knapsack constraint redundant
9789  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9790  * redundancy effect:
9791  * wi' := capacity - cliqueweightsum(xi == v)
9792  * this rule can also be applied to binary variables not in the knapsack!
9793  */
9794 static
9796  SCIP* scip, /**< SCIP data structure */
9797  SCIP_CONS* cons, /**< knapsack constraint */
9798  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9799  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9800  )
9801 {
9802  SCIP_CONSDATA* consdata;
9803  SCIP_VAR** binvars;
9804  int nbinvars;
9805  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9806  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9807  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9808  int* zeroitems; /* item number in knapsack that is implied to zero */
9809  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9810  int zeroitemssize;
9811  int nzeroitems;
9812  SCIP_Bool* zeroiteminserted[2];
9813  SCIP_Bool memlimitreached;
9814  int nliftcands[2];
9815  SCIP_Bool* cliqueused;
9816  SCIP_Bool* itemremoved;
9817  SCIP_Longint maxcliqueweightsum;
9818  SCIP_VAR** addvars;
9819  SCIP_Longint* addweights;
9820  SCIP_Longint addweightsum;
9821  int nvars;
9822  int cliquenum;
9823  int naddvars;
9824  int val;
9825  int i;
9826 
9827  int* tmpindices;
9828  SCIP_Bool* tmpboolindices;
9829  int* tmpindices2;
9830  SCIP_Bool* tmpboolindices2;
9831  int* tmpindices3;
9832  SCIP_Bool* tmpboolindices3;
9833  int tmp;
9834  int tmp2;
9835  int tmp3;
9836  SCIP_CONSHDLR* conshdlr;
9837  SCIP_CONSHDLRDATA* conshdlrdata;
9838 
9839  assert(nchgcoefs != NULL);
9840  assert(!SCIPconsIsModifiable(cons));
9841 
9842  consdata = SCIPconsGetData(cons);
9843  assert(consdata != NULL);
9844  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9845  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9846  assert(consdata->nvars > 0);
9847  assert(consdata->merged);
9848 
9849  nvars = consdata->nvars;
9850 
9851  /* check if the knapsack has too many items/cliques for applying this costly method */
9852  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9853  return SCIP_OKAY;
9854 
9855  /* sort items, s.t. the heaviest one is in the first position */
9856  sortItems(consdata);
9857 
9858  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9859  return SCIP_OKAY;
9860 
9861  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9862  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9863  assert(nbinvars > 0);
9864  binvars = SCIPgetVars(scip);
9865 
9866  /* get conshdlrdata to use cleared memory */
9867  conshdlr = SCIPconsGetHdlr(cons);
9868  assert(conshdlr != NULL);
9869  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9870  assert(conshdlrdata != NULL);
9871 
9872  /* allocate temporary memory for the list of implied to zero variables */
9873  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9874  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9875  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9876 
9877  assert(conshdlrdata->ints1size > 0);
9878  assert(conshdlrdata->ints2size > 0);
9879  assert(conshdlrdata->longints1size > 0);
9880  assert(conshdlrdata->longints2size > 0);
9881 
9882  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9883  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9884  * transform all integers into their binary representation then it maybe happens
9885  */
9886  if( conshdlrdata->ints1size < nbinvars )
9887  {
9888  int oldsize = conshdlrdata->ints1size;
9889 
9890  conshdlrdata->ints1size = nbinvars;
9891  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9892  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9893  }
9894  if( conshdlrdata->ints2size < nbinvars )
9895  {
9896  int oldsize = conshdlrdata->ints2size;
9897 
9898  conshdlrdata->ints2size = nbinvars;
9899  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9900  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9901  }
9902  if( conshdlrdata->longints1size < nbinvars )
9903  {
9904  int oldsize = conshdlrdata->longints1size;
9905 
9906  conshdlrdata->longints1size = nbinvars;
9907  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9908  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9909  }
9910  if( conshdlrdata->longints2size < nbinvars )
9911  {
9912  int oldsize = conshdlrdata->longints2size;
9913 
9914  conshdlrdata->longints2size = nbinvars;
9915  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9916  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9917  }
9918 
9919  firstidxs[0] = conshdlrdata->ints1;
9920  firstidxs[1] = conshdlrdata->ints2;
9921  zeroweightsums[0] = conshdlrdata->longints1;
9922  zeroweightsums[1] = conshdlrdata->longints2;
9923 
9924  /* check for cleared arrays, all entries are zero */
9925 #ifndef NDEBUG
9926  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9927  {
9928  assert(firstidxs[0][tmp] == 0);
9929  assert(firstidxs[1][tmp] == 0);
9930  assert(zeroweightsums[0][tmp] == 0);
9931  assert(zeroweightsums[1][tmp] == 0);
9932  }
9933 #endif
9934 
9935  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9936  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9937 
9938  zeroitems[0] = -1; /* dummy element */
9939  nextidxs[0] = -1;
9940  nzeroitems = 1;
9941  nliftcands[0] = 0;
9942  nliftcands[1] = 0;
9943 
9944  assert(conshdlrdata->bools1size > 0);
9945  assert(conshdlrdata->bools2size > 0);
9946 
9947  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9948  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9949  * transform all integers into their binary representation then it maybe happens
9950  */
9951  if( conshdlrdata->bools1size < nbinvars )
9952  {
9953  int oldsize = conshdlrdata->bools1size;
9954 
9955  conshdlrdata->bools1size = nbinvars;
9956  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9957  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9958  }
9959  if( conshdlrdata->bools2size < nbinvars )
9960  {
9961  int oldsize = conshdlrdata->bools2size;
9962 
9963  conshdlrdata->bools2size = nbinvars;
9964  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9965  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9966  }
9967 
9968  zeroiteminserted[0] = conshdlrdata->bools1;
9969  zeroiteminserted[1] = conshdlrdata->bools2;
9970 
9971  /* check for cleared arrays, all entries are zero */
9972 #ifndef NDEBUG
9973  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9974  {
9975  assert(zeroiteminserted[0][tmp] == 0);
9976  assert(zeroiteminserted[1][tmp] == 0);
9977  }
9978 #endif
9979 
9980  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9981  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9982  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9983  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9984  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9985  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9986 
9987  tmp2 = 0;
9988  tmp3 = 0;
9989 
9990  memlimitreached = FALSE;
9991  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9992  {
9993  SCIP_CLIQUE** cliques;
9994  SCIP_VAR* var;
9995  SCIP_Longint weight;
9996  SCIP_Bool value;
9997  int varprobindex;
9998  int ncliques;
9999  int j;
10000 
10001  tmp = 0;
10002 
10003  /* get corresponding active problem variable */
10004  var = consdata->vars[i];
10005  weight = consdata->weights[i];
10006  value = TRUE;
10007  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10008  varprobindex = SCIPvarGetProbindex(var);
10009  assert(0 <= varprobindex && varprobindex < nbinvars);
10010 
10011  /* update the zeroweightsum */
10012  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10013  tmpboolindices3[tmp3] = !value;
10014  tmpindices3[tmp3] = varprobindex;
10015  ++tmp3;
10016 
10017  /* initialize the arrays of inserted zero items */
10018  /* first add the implications (~x == 1 -> x == 0) */
10019  {
10020  SCIP_Bool implvalue;
10021  int probindex;
10022 
10023  probindex = SCIPvarGetProbindex(var);
10024  assert(0 <= probindex && probindex < nbinvars);
10025 
10026  implvalue = !value;
10027 
10028  /* insert the item into the list of the implied variable/value */
10029  assert( !zeroiteminserted[implvalue][probindex] );
10030 
10031  if( firstidxs[implvalue][probindex] == 0 )
10032  {
10033  tmpboolindices2[tmp2] = implvalue;
10034  tmpindices2[tmp2] = probindex;
10035  ++tmp2;
10036  }
10037  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10038  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10039  &memlimitreached) );
10040  zeroiteminserted[implvalue][probindex] = TRUE;
10041  tmpboolindices[tmp] = implvalue;
10042  tmpindices[tmp] = probindex;
10043  ++tmp;
10044  }
10045 
10046  /* get the cliques where the knapsack item is member of with value 1 */
10047  ncliques = SCIPvarGetNCliques(var, value);
10048  cliques = SCIPvarGetCliques(var, value);
10049  for( j = 0; j < ncliques && !memlimitreached; ++j )
10050  {
10051  SCIP_VAR** cliquevars;
10052  SCIP_Bool* cliquevalues;
10053  int ncliquevars;
10054  int k;
10055 
10056  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10057 
10058  /* discard big cliques */
10059  if( ncliquevars > MAX_CLIQUELENGTH )
10060  continue;
10061 
10062  cliquevars = SCIPcliqueGetVars(cliques[j]);
10063  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10064 
10065  for( k = ncliquevars - 1; k >= 0; --k )
10066  {
10067  SCIP_Bool implvalue;
10068  int probindex;
10069 
10070  if( var == cliquevars[k] )
10071  continue;
10072 
10073  probindex = SCIPvarGetProbindex(cliquevars[k]);
10074  if( probindex == -1 )
10075  continue;
10076 
10077  assert(0 <= probindex && probindex < nbinvars);
10078  implvalue = cliquevalues[k];
10079 
10080  /* insert the item into the list of the clique variable/value */
10081  if( !zeroiteminserted[implvalue][probindex] )
10082  {
10083  if( firstidxs[implvalue][probindex] == 0 )
10084  {
10085  tmpboolindices2[tmp2] = implvalue;
10086  tmpindices2[tmp2] = probindex;
10087  ++tmp2;
10088  }
10089 
10090  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10091  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10092  &memlimitreached) );
10093  zeroiteminserted[implvalue][probindex] = TRUE;
10094  tmpboolindices[tmp] = implvalue;
10095  tmpindices[tmp] = probindex;
10096  ++tmp;
10097 
10098  if( memlimitreached )
10099  break;
10100  }
10101  }
10102  }
10103  /* clear zeroiteminserted */
10104  for( --tmp; tmp >= 0; --tmp)
10105  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10106  }
10107  SCIPfreeBufferArray(scip, &tmpboolindices);
10108 
10109  /* calculate the clique partition and the maximal sum of weights using the clique information */
10110  assert(consdata->sorted);
10111  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10112 
10113  assert(conshdlrdata->bools3size > 0);
10114 
10115  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10116  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10117  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10118  */
10119  if( conshdlrdata->bools3size < consdata->nvars )
10120  {
10121  int oldsize = conshdlrdata->bools3size;
10122 
10123  conshdlrdata->bools3size = consdata->nvars;;
10124  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10125  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10126  }
10127 
10128  cliqueused = conshdlrdata->bools3;
10129 
10130  /* check for cleared array, all entries are zero */
10131 #ifndef NDEBUG
10132  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10133  assert(cliqueused[tmp] == 0);
10134 #endif
10135 
10136  maxcliqueweightsum = 0;
10137  tmp = 0;
10138 
10139  /* calculates maximal weight of cliques */
10140  for( i = 0; i < consdata->nvars; ++i )
10141  {
10142  cliquenum = consdata->cliquepartition[i];
10143  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10144 
10145  if( !cliqueused[cliquenum] )
10146  {
10147  maxcliqueweightsum += consdata->weights[i];
10148  cliqueused[cliquenum] = TRUE;
10149  tmpindices[tmp] = cliquenum;
10150  ++tmp;
10151  }
10152  }
10153  /* clear cliqueused */
10154  for( --tmp; tmp >= 0; --tmp)
10155  cliqueused[tmp] = FALSE;
10156 
10157  assert(conshdlrdata->bools4size > 0);
10158 
10159  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10160  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10161  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10162  */
10163  if( conshdlrdata->bools4size < consdata->nvars )
10164  {
10165  int oldsize = conshdlrdata->bools4size;
10166 
10167  conshdlrdata->bools4size = consdata->nvars;
10168  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10169  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10170  }
10171 
10172  itemremoved = conshdlrdata->bools4;
10173 
10174  /* check for cleared array, all entries are zero */
10175 #ifndef NDEBUG
10176  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10177  assert(itemremoved[tmp] == 0);
10178 #endif
10179 
10180  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10181  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10182  * included in subsequent cliqueweightsum calculations)
10183  */
10184  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10185  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10186  naddvars = 0;
10187  addweightsum = 0;
10188  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10189  {
10190  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10191  {
10192  SCIP_Longint cliqueweightsum;
10193  int probindex;
10194  int idx;
10195  int j;
10196 
10197  tmp = 0;
10198 
10199  probindex = liftcands[val][i];
10200  assert(0 <= probindex && probindex < nbinvars);
10201 
10202  /* ignore empty zero lists and variables that cannot be lifted anyways */
10203  if( firstidxs[val][probindex] == 0
10204  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10205  continue;
10206 
10207  /* mark the items that are implied to zero by setting the current variable to the current value */
10208  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10209  {
10210  assert(0 < idx && idx < nzeroitems);
10211  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10212  itemremoved[zeroitems[idx]] = TRUE;
10213  }
10214 
10215  /* calculate the residual cliqueweight sum */
10216  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10217  for( j = 0; j < consdata->nvars; ++j )
10218  {
10219  cliquenum = consdata->cliquepartition[j];
10220  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10221  if( !itemremoved[j] )
10222  {
10223  if( !cliqueused[cliquenum] )
10224  {
10225  cliqueweightsum += consdata->weights[j];
10226  cliqueused[cliquenum] = TRUE;
10227  tmpindices[tmp] = cliquenum;
10228  ++tmp;
10229  }
10230 
10231  if( cliqueweightsum >= consdata->capacity )
10232  break;
10233  }
10234  }
10235 
10236  /* check if the weight of the variable/value can be increased */
10237  if( cliqueweightsum < consdata->capacity )
10238  {
10239  SCIP_VAR* var;
10240  SCIP_Longint weight;
10241 
10242  /* insert the variable (with value TRUE) in the list of additional items */
10243  assert(naddvars < 2*nbinvars);
10244  var = binvars[probindex];
10245  if( val == FALSE )
10246  {
10247  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10248  }
10249  weight = consdata->capacity - cliqueweightsum;
10250  addvars[naddvars] = var;
10251  addweights[naddvars] = weight;
10252  addweightsum += weight;
10253  naddvars++;
10254 
10255  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10256  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10257  }
10258 
10259  /* clear itemremoved */
10260  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10261  {
10262  assert(0 < idx && idx < nzeroitems);
10263  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10264  itemremoved[zeroitems[idx]] = FALSE;
10265  }
10266  /* clear cliqueused */
10267  for( --tmp; tmp >= 0; --tmp)
10268  cliqueused[tmpindices[tmp]] = FALSE;
10269  }
10270  }
10271 
10272  /* clear part of zeroweightsums */
10273  for( --tmp3; tmp3 >= 0; --tmp3)
10274  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10275 
10276  /* clear rest of zeroweightsums and firstidxs */
10277  for( --tmp2; tmp2 >= 0; --tmp2)
10278  {
10279  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10280  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10281  }
10282 
10283  /* add all additional item weights */
10284  for( i = 0; i < naddvars; ++i )
10285  {
10286  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10287  }
10288  *nchgcoefs += naddvars;
10289 
10290  if( naddvars > 0 )
10291  {
10292  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10293  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10294  }
10295 
10296  /* free temporary memory */
10297  SCIPfreeBufferArray(scip, &addweights);
10298  SCIPfreeBufferArray(scip, &addvars);
10299  SCIPfreeBufferArray(scip, &tmpindices);
10300  SCIPfreeBufferArray(scip, &tmpindices2);
10301  SCIPfreeBufferArray(scip, &tmpindices3);
10302  SCIPfreeBufferArray(scip, &tmpboolindices2);
10303  SCIPfreeBufferArray(scip, &tmpboolindices3);
10304  SCIPfreeBufferArray(scip, &nextidxs);
10305  SCIPfreeBufferArray(scip, &zeroitems);
10306  SCIPfreeBufferArray(scip, &liftcands[1]);
10307  SCIPfreeBufferArray(scip, &liftcands[0]);
10308 
10309  return SCIP_OKAY;
10310 }
10311 
10312 /** tightens item weights and capacity in presolving:
10313  * given a knapsack sum(wi*xi) <= capacity
10314  * (1) let weightsum := sum(wi)
10315  * if weightsum - wi < capacity:
10316  * - not using item i would make the knapsack constraint redundant
10317  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10318  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10319  * - change coefficients:
10320  * wi' := weightsum - capacity
10321  * capacity' := capacity - (wi - wi')
10322  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10323  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10324  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10325  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10326  * can be multiple times the same weight, this can be improved
10327  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10328  * weight, to capacity - lastmininmalweightsum, e.g. :
10329  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10330  * -> minimal weightsums: 5, 5, 10, 10
10331  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10332  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10333  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10334  * (3) let W(C) be the maximal weight of clique C,
10335  * cliqueweightsum := sum(W(C))
10336  * if cliqueweightsum - W(C) < capacity:
10337  * - not using any item of C would make the knapsack constraint redundant
10338  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10339  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10340  * - change coefficients:
10341  * delta := capacity - (cliqueweightsum - W(C))
10342  * wi' := max(wi - delta, 0)
10343  * capacity' := capacity - delta
10344  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10345  * introduce infeasible solutions.
10346  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10347  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10348  * if cliqueweightsum(xi == v) < capacity:
10349  * - fixing variable xi to v would make the knapsack constraint redundant
10350  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10351  * redundancy effect:
10352  * wi' := capacity - cliqueweightsum(xi == v)
10353  * This rule can also be applied to binary variables not in the knapsack!
10354  * (5) if min{w} + wi > capacity:
10355  * - using item i would force to fix other items to zero
10356  * - wi can be increased to the capacity
10357  */
10358 static
10360  SCIP* scip, /**< SCIP data structure */
10361  SCIP_CONS* cons, /**< knapsack constraint */
10362  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10363  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10364  int* nchgsides, /**< pointer to count number of side changes */
10365  int* naddconss, /**< pointer to count number of added constraints */
10366  int* ndelconss, /**< pointer to count number of deleted constraints */
10367  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10368  )
10369 {
10370  SCIP_CONSHDLRDATA* conshdlrdata;
10371  SCIP_CONSDATA* consdata;
10372  SCIP_Longint* weights;
10373  SCIP_Longint sumcoef;
10374  SCIP_Longint capacity;
10375  SCIP_Longint newweight;
10376  SCIP_Longint maxweight;
10377  SCIP_Longint minweight;
10378  SCIP_Bool sumcoefcase = FALSE;
10379  int startpos;
10380  int backpos;
10381  int nvars;
10382  int pos;
10383  int k;
10384  int i;
10385 
10386  assert(nchgcoefs != NULL);
10387  assert(nchgsides != NULL);
10388  assert(!SCIPconsIsModifiable(cons));
10389 
10390  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10391  assert(conshdlrdata != NULL);
10392 
10393  consdata = SCIPconsGetData(cons);
10394  assert(consdata != NULL);
10395  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10396  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10397  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10398  assert(consdata->nvars > 0);
10399 
10400  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10401  if( *cutoff )
10402  return SCIP_OKAY;
10403 
10404  /* apply rule (1) */
10405  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10406  {
10407  do
10408  {
10409  assert(consdata->merged);
10410 
10411  /* sort items, s.t. the heaviest one is in the first position */
10412  sortItems(consdata);
10413 
10414  for( i = 0; i < consdata->nvars; ++i )
10415  {
10416  SCIP_Longint weight;
10417 
10418  weight = consdata->weights[i];
10419  if( consdata->weightsum - weight < consdata->capacity )
10420  {
10421  newweight = consdata->weightsum - consdata->capacity;
10422  consdataChgWeight(consdata, i, newweight);
10423  consdata->capacity -= (weight - newweight);
10424  (*nchgcoefs)++;
10425  (*nchgsides)++;
10426  assert(!consdata->sorted);
10427  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",
10428  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10429  consdata->capacity + (weight-newweight), consdata->capacity);
10430  }
10431  else
10432  break;
10433  }
10434  }
10435  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10436  }
10437 
10438  /* check for redundancy */
10439  if( consdata->weightsum <= consdata->capacity )
10440  return SCIP_OKAY;
10441 
10442  pos = 0;
10443  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10444  ++pos;
10445 
10446  sumcoef = 0;
10447  weights = consdata->weights;
10448  nvars = consdata->nvars;
10449  capacity = consdata->capacity;
10450 
10451  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10452  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10453  {
10454  /* further reductions using the next possible coefficient sum
10455  *
10456  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10457  */
10458  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10459  for( k = 0; k < 4; ++k )
10460  {
10461  newweight = capacity - sumcoef;
10462 
10463  /* determine next minimal coefficient sum */
10464  switch( k )
10465  {
10466  case 0:
10467  sumcoef = weights[nvars - 1];
10468  backpos = nvars - 1;
10469  break;
10470  case 1:
10471  sumcoef = weights[nvars - 2];
10472  backpos = nvars - 2;
10473  break;
10474  case 2:
10475  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10476  {
10477  sumcoefcase = TRUE;
10478  sumcoef = weights[nvars - 3];
10479  backpos = nvars - 3;
10480  }
10481  else
10482  {
10483  sumcoefcase = FALSE;
10484  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10485  backpos = nvars - 2;
10486  }
10487  break;
10488  default:
10489  assert(k == 3);
10490  if( sumcoefcase )
10491  {
10492  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10493  {
10494  sumcoef = weights[nvars - 4];
10495  backpos = nvars - 4;
10496  }
10497  else
10498  {
10499  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10500  backpos = nvars - 2;
10501  }
10502  }
10503  else
10504  {
10505  sumcoef = weights[nvars - 3];
10506  backpos = nvars - 3;
10507  }
10508  break;
10509  }
10510 
10511  if( backpos <= pos )
10512  break;
10513 
10514  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10515  maxweight = weights[pos];
10516  startpos = pos;
10517  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10518  {
10519  assert(newweight > weights[pos]);
10520 
10521  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10522  SCIPconsGetName(cons), maxweight, newweight);
10523 
10524  consdataChgWeight(consdata, pos, newweight);
10525 
10526  ++pos;
10527  assert(pos < nvars);
10528 
10529  maxweight = weights[pos];
10530 
10531  if( backpos <= pos )
10532  break;
10533  }
10534  (*nchgcoefs) += (pos - startpos);
10535 
10536  /* skip unchangable weights */
10537  while( pos < nvars && weights[pos] + sumcoef == capacity )
10538  ++pos;
10539 
10540  /* check special case were there is only one weight left to tighten
10541  *
10542  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10543  *
10544  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10545  *
10546  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10547  */
10548  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10549  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10550  {
10551  newweight = capacity - sumcoef;
10552  assert(newweight > weights[pos]);
10553 
10554  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10555  SCIPconsGetName(cons), maxweight, newweight);
10556 
10557  consdataChgWeight(consdata, pos, newweight);
10558 
10559  break;
10560  }
10561 
10562  if( backpos <= pos )
10563  break;
10564  }
10565  }
10566 
10567  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10568  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10569  {
10570  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10571  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10572  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10573  {
10574  SCIP_VAR** clqvars;
10575  SCIP_CONS* cliquecons;
10576  char name[SCIP_MAXSTRLEN];
10577  int* clqpart;
10578  int nclqvars;
10579  int nclq;
10580  int len;
10581  int c;
10582  int w;
10583 
10584  assert(!SCIPconsIsDeleted(cons));
10585 
10586  if( pos == consdata->nvars )
10587  {
10588  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10589 
10590  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10594  SCIPconsIsStickingAtNode(cons)) );
10595 
10596  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10597  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10598  ++(*naddconss);
10599 
10600  /* delete old constraint */
10601  SCIP_CALL( SCIPdelCons(scip, cons) );
10602  ++(*ndelconss);
10603 
10604  return SCIP_OKAY;
10605  }
10606 
10607  len = consdata->nvars - pos;
10608 
10609  /* allocate temporary memory */
10610  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10611 
10612  /* calculate clique partition */
10613  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10614  assert(nclq <= len);
10615 
10616 #ifndef NDEBUG
10617  /* clique numbers must be at least as high as the index */
10618  for( w = 0; w < nclq; ++w )
10619  assert(clqpart[w] <= w);
10620 #endif
10621 
10622  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10623 
10624  /* allocate temporary memory */
10625  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10626 
10627  /* copy corresponding variables with big coefficients */
10628  for( w = pos - 1; w >= 0; --w )
10629  clqvars[w] = consdata->vars[w];
10630 
10631  /* create for each clique a set-packing constraint */
10632  for( c = 0; c < nclq; ++c )
10633  {
10634  nclqvars = pos;
10635 
10636  for( w = c; w < len; ++w )
10637  {
10638  if( clqpart[w] == c )
10639  {
10640  assert(nclqvars < pos + len - nclq + 1);
10641  clqvars[nclqvars] = consdata->vars[w + pos];
10642  ++nclqvars;
10643  }
10644  }
10645 
10646  assert(nclqvars > 1);
10647 
10648  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10649  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10653  SCIPconsIsStickingAtNode(cons)) );
10654  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10655  SCIPdebugPrintCons(scip, cliquecons, NULL);
10656  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10657  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10658  ++(*naddconss);
10659  }
10660 
10661  /* delete old constraint */
10662  SCIP_CALL( SCIPdelCons(scip, cons) );
10663  ++(*ndelconss);
10664 
10665  SCIPfreeBufferArray(scip, &clqvars);
10666  SCIPfreeBufferArray(scip, &clqpart);
10667 
10668  return SCIP_OKAY;
10669  }
10670  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10671  {
10672  SCIP_Longint* maxcliqueweights;
10673  SCIP_Longint* newweightvals;
10674  int* newweightidxs;
10675  SCIP_Longint cliqueweightsum;
10676 
10677  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10678  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10679  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10680 
10681  /* repeat as long as changes have been applied */
10682  do
10683  {
10684  int ncliques;
10685  int cliquenum;
10686  SCIP_Bool zeroweights;
10687 
10688  assert(consdata->merged);
10689 
10690  /* sort items, s.t. the heaviest one is in the first position */
10691  sortItems(consdata);
10692 
10693  /* calculate a clique partition */
10694  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10695 
10696  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10697  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10698  break;
10699 
10700  /* calculate the maximal weight of the cliques and store the clique type */
10701  cliqueweightsum = 0;
10702  ncliques = 0;
10703 
10704  for( i = 0; i < consdata->nvars; ++i )
10705  {
10706  SCIP_Longint weight;
10707 
10708  cliquenum = consdata->cliquepartition[i];
10709  assert(0 <= cliquenum && cliquenum <= ncliques);
10710 
10711  weight = consdata->weights[i];
10712  assert(weight > 0);
10713 
10714  if( cliquenum == ncliques )
10715  {
10716  maxcliqueweights[ncliques] = weight;
10717  cliqueweightsum += weight;
10718  ++ncliques;
10719  }
10720 
10721  assert(maxcliqueweights[cliquenum] >= weight);
10722  }
10723 
10724  /* apply rule on every clique */
10725  zeroweights = FALSE;
10726  for( i = 0; i < ncliques; ++i )
10727  {
10728  SCIP_Longint delta;
10729 
10730  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10731  if( delta > 0 )
10732  {
10733  SCIP_Longint newcapacity;
10734 #ifndef NDEBUG
10735  SCIP_Longint newmincliqueweight;
10736 #endif
10737  SCIP_Longint newminweightsuminclique;
10738  SCIP_Bool forceclique;
10739  int nnewweights;
10740  int j;
10741 
10742  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",
10743  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10744  newcapacity = consdata->capacity - delta;
10745  forceclique = FALSE;
10746  nnewweights = 0;
10747 #ifndef NDEBUG
10748  newmincliqueweight = newcapacity + 1;
10749  for( j = 0; j < i; ++j )
10750  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10751 #endif
10752  for( j = i; j < consdata->nvars; ++j )
10753  {
10754  if( consdata->cliquepartition[j] == i )
10755  {
10756  newweight = consdata->weights[j] - delta;
10757  newweight = MAX(newweight, 0);
10758 
10759  /* cache the new weight */
10760  assert(nnewweights < consdata->nvars);
10761  newweightvals[nnewweights] = newweight;
10762  newweightidxs[nnewweights] = j;
10763  nnewweights++;
10764 
10765 #ifndef NDEBUG
10766  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10767  newmincliqueweight = newweight;
10768 #endif
10769  }
10770  }
10771 
10772  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10773  if( nnewweights > 1 )
10774  {
10775 #ifndef NDEBUG
10776  j = newweightidxs[nnewweights - 2];
10777  assert(0 <= j && j < consdata->nvars);
10778  assert(consdata->cliquepartition[j] == i);
10779  j = newweightidxs[nnewweights - 1];
10780  assert(0 <= j && j < consdata->nvars);
10781  assert(consdata->cliquepartition[j] == i);
10782 #endif
10783 
10784  newminweightsuminclique = newweightvals[nnewweights - 2];
10785  newminweightsuminclique += newweightvals[nnewweights - 1];
10786 
10787  /* check if these new two minimal weights both fit into the knapsack;
10788  * if this is true, we have to add a clique constraint in order to enforce the clique
10789  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10790  * reduction might be infeasible, i.e., allows additional solutions)
10791  */
10792  if( newminweightsuminclique <= newcapacity )
10793  forceclique = TRUE;
10794  }
10795 
10796  /* check if we really want to apply the change */
10797  if( conshdlrdata->disaggregation || !forceclique )
10798  {
10799  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10800  consdata->capacity, newcapacity, forceclique);
10801  consdata->capacity = newcapacity;
10802  (*nchgsides)++;
10803 
10804  for( k = 0; k < nnewweights; ++k )
10805  {
10806  j = newweightidxs[k];
10807  assert(0 <= j && j < consdata->nvars);
10808  assert(consdata->cliquepartition[j] == i);
10809 
10810  /* apply the weight change */
10811  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10812  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10813  consdataChgWeight(consdata, j, newweightvals[k]);
10814  (*nchgcoefs)++;
10815  assert(!consdata->sorted);
10816  zeroweights = zeroweights || (newweightvals[k] == 0);
10817  }
10818  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10819  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10820  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10821  * knapsack constraint
10822  */
10823  if( forceclique )
10824  {
10825  SCIP_CONS* cliquecons;
10826  char name[SCIP_MAXSTRLEN];
10827  SCIP_VAR** cliquevars;
10828 
10829  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10830  for( k = 0; k < nnewweights; ++k )
10831  cliquevars[k] = consdata->vars[newweightidxs[k]];
10832 
10833  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10834  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10838  SCIPconsIsStickingAtNode(cons)) );
10839  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10840  SCIPdebugPrintCons(scip, cliquecons, NULL);
10841  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10842  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10843  SCIPfreeBufferArray(scip, &cliquevars);
10844  (*naddconss)++;
10845  }
10846  }
10847  }
10848  }
10849  if( zeroweights )
10850  {
10851  SCIP_CALL( removeZeroWeights(scip, cons) );
10852  }
10853  }
10854  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10855 
10856  /* free temporary memory */
10857  SCIPfreeBufferArray(scip, &newweightidxs);
10858  SCIPfreeBufferArray(scip, &newweightvals);
10859  SCIPfreeBufferArray(scip, &maxcliqueweights);
10860 
10861  /* check for redundancy */
10862  if( consdata->weightsum <= consdata->capacity )
10863  return SCIP_OKAY;
10864  }
10865  }
10866 
10867  /* apply rule (3) */
10868  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10869  {
10870  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10871  }
10872 
10873  /* check for redundancy */
10874  if( consdata->weightsum <= consdata->capacity )
10875  return SCIP_OKAY;
10876 
10877  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10878  {
10879  /* apply rule (4) (all but smallest weight) */
10880  assert(consdata->merged);
10881  sortItems(consdata);
10882  minweight = consdata->weights[consdata->nvars-1];
10883  for( i = 0; i < consdata->nvars-1; ++i )
10884  {
10885  SCIP_Longint weight;
10886 
10887  weight = consdata->weights[i];
10888  assert(weight >= minweight);
10889  if( minweight + weight > consdata->capacity )
10890  {
10891  if( weight < consdata->capacity )
10892  {
10893  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10894  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10895  assert(consdata->sorted);
10896  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10897  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10898  consdata->sorted = TRUE;
10899  (*nchgcoefs)++;
10900  }
10901  }
10902  else
10903  break;
10904  }
10905 
10906  /* apply rule (5) (smallest weight) */
10907  if( consdata->nvars >= 2 )
10908  {
10909  SCIP_Longint weight;
10910 
10911  minweight = consdata->weights[consdata->nvars-2];
10912  weight = consdata->weights[consdata->nvars-1];
10913  assert(minweight >= weight);
10914  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10915  {
10916  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10917  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10918  assert(consdata->sorted);
10919  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10920  assert(minweight >= consdata->weights[consdata->nvars-1]);
10921  consdata->sorted = TRUE;
10922  (*nchgcoefs)++;
10923  }
10924  }
10925  }
10926 
10927  return SCIP_OKAY;
10928 }
10929 
10930 
10931 #ifdef SCIP_DEBUG
10932 static
10933 void printClique(
10934  SCIP_VAR** cliquevars,
10935  int ncliquevars
10936  )
10937 {
10938  int b;
10939  SCIPdebugMessage("adding new Clique: ");
10940  for( b = 0; b < ncliquevars; ++b )
10941  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10942  SCIPdebugPrintf("\n");
10943 }
10944 #endif
10945 
10946 /** adds negated cliques of the knapsack constraint to the global clique table */
10947 static
10949  SCIP*const scip, /**< SCIP data structure */
10950  SCIP_CONS*const cons, /**< knapsack constraint */
10951  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10952  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10953  )
10954 {
10955  SCIP_CONSDATA* consdata;
10956  SCIP_CONSHDLRDATA* conshdlrdata;
10957  SCIP_VAR** poscliquevars;
10958  SCIP_VAR** cliquevars;
10959  SCIP_Longint* maxweights;
10960  SCIP_Longint* gainweights;
10961  int* gaincliquepartition;
10962  SCIP_Bool* cliqueused;
10963  SCIP_Longint minactduetonegcliques;
10964  SCIP_Longint freecapacity;
10965  SCIP_Longint lastweight;
10966  SCIP_Longint beforelastweight;
10967  int nposcliquevars;
10968  int ncliquevars;
10969  int nvars;
10970  int nnegcliques;
10971  int lastcliqueused;
10972  int thisnbdchgs;
10973  int v;
10974  int w;
10975 
10976  assert(scip != NULL);
10977  assert(cons != NULL);
10978  assert(cutoff != NULL);
10979  assert(nbdchgs != NULL);
10980 
10981  *cutoff = FALSE;
10982 
10983  consdata = SCIPconsGetData(cons);
10984  assert(consdata != NULL);
10985 
10986  nvars = consdata->nvars;
10987 
10988  /* check whether the cliques have already been added */
10989  if( consdata->cliquesadded || nvars == 0 )
10990  return SCIP_OKAY;
10991 
10992  /* make sure, the items are merged */
10993  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10994  if( *cutoff )
10995  return SCIP_OKAY;
10996 
10997  /* make sure, items are sorted by non-increasing weight */
10998  sortItems(consdata);
10999 
11000  assert(consdata->merged);
11001 
11002  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11003  assert(conshdlrdata != NULL);
11004 
11005  /* calculate a clique partition */
11006  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11007  nnegcliques = consdata->nnegcliques;
11008 
11009  /* if we have no negated cliques, stop */
11010  if( nnegcliques == nvars )
11011  return SCIP_OKAY;
11012 
11013  /* get temporary memory */
11014  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11015  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11016  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11017  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11018  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11019  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11020 
11021  nnegcliques = 0;
11022  minactduetonegcliques = 0;
11023 
11024  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11025  for( v = 0; v < nvars; ++v )
11026  {
11027  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11028  assert(consdata->weights[v] > 0);
11029 
11030  if( consdata->negcliquepartition[v] == nnegcliques )
11031  {
11032  nnegcliques++;
11033  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11034  }
11035  else
11036  minactduetonegcliques += consdata->weights[v];
11037  }
11038 
11039  nposcliquevars = 0;
11040 
11041  /* add cliques, using negated cliques information */
11042  if( minactduetonegcliques > 0 )
11043  {
11044  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11045  freecapacity = consdata->capacity - minactduetonegcliques;
11046 
11047  SCIPdebugPrintCons(scip, cons, NULL);
11048  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",
11049  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11050 
11051  /* calculate possible gain by switching chosen items in negated cliques */
11052  for( v = 0; v < nvars; ++v )
11053  {
11054  if( !cliqueused[consdata->negcliquepartition[v]] )
11055  {
11056  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11057  for( w = v + 1; w < nvars; ++w )
11058  {
11059  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11060  * weight[w] (which are both in a negated clique) */
11061  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11062  && consdata->weights[v] > consdata->weights[w] )
11063  {
11064  poscliquevars[nposcliquevars] = consdata->vars[w];
11065  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11066  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11067  ++nposcliquevars;
11068  }
11069  }
11070  }
11071  }
11072 
11073  /* try to create negated cliques */
11074  if( nposcliquevars > 0 )
11075  {
11076  /* sort possible gain per substitution of the clique members */
11077  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11078 
11079  for( v = 0; v < nposcliquevars; ++v )
11080  {
11081  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11082  ncliquevars = 1;
11083  lastweight = gainweights[v];
11084  beforelastweight = -1;
11085  lastcliqueused = gaincliquepartition[v];
11086  /* clear cliqueused to get an unused array */
11087  BMSclearMemoryArray(cliqueused, nnegcliques);
11088  cliqueused[gaincliquepartition[v]] = TRUE;
11089 
11090  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11091  * in the same negated clique and by taking two of them would exceed the free capacity */
11092  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11093  {
11094  beforelastweight = lastweight;
11095  lastweight = gainweights[w];
11096  lastcliqueused = gaincliquepartition[w];
11097  cliqueused[gaincliquepartition[w]] = TRUE;
11098  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11099  ++ncliquevars;
11100  }
11101 
11102  if( ncliquevars > 1 )
11103  {
11104  SCIPdebug( printClique(cliquevars, ncliquevars) );
11105  assert(beforelastweight > 0);
11106  /* add the clique to the clique table */
11107  /* this really happens, e.g., on enigma.mps from the short test set */
11108  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11109  if( *cutoff )
11110  goto TERMINATE;
11111  *nbdchgs += thisnbdchgs;
11112 
11113  /* reset last used clique to get slightly different cliques */
11114  cliqueused[lastcliqueused] = FALSE;
11115 
11116  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11117  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11118  {
11119  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11120  SCIPdebug( printClique(cliquevars, ncliquevars) );
11121  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11122  if( *cutoff )
11123  goto TERMINATE;
11124  *nbdchgs += thisnbdchgs;
11125  }
11126  }
11127  }
11128  }
11129  }
11130 
11131  TERMINATE:
11132  /* free temporary memory */
11133  SCIPfreeBufferArray(scip, &cliqueused);
11134  SCIPfreeBufferArray(scip, &maxweights);
11135  SCIPfreeBufferArray(scip, &gaincliquepartition);
11136  SCIPfreeBufferArray(scip, &gainweights);
11137  SCIPfreeBufferArray(scip, &cliquevars);
11138  SCIPfreeBufferArray(scip, &poscliquevars);
11139 
11140  return SCIP_OKAY;
11141 }
11142 
11143 /** greedy clique detection by considering weights and capacity
11144  *
11145  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11146  * 1) neighboring items which exceed the capacity together => one clique
11147  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11148  */
11149 static
11151  SCIP*const scip, /**< SCIP data structure */
11152  SCIP_VAR** items, /**< array of variable items */
11153  SCIP_Longint* weights, /**< weights of the items */
11154  int nitems, /**< the number of items */
11155  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11156  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11157  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11158  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11159  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11160  )
11161 {
11162  SCIP_Longint lastweight;
11163  int ncliquevars;
11164  int i;
11165  int thisnbdchgs;
11166 
11167  if( nitems <= 1 )
11168  return SCIP_OKAY;
11169 
11170  /* sort possible gain per substitution of the clique members */
11171  if( ! sorteditems )
11172  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11173 
11174  ncliquevars = 1;
11175  lastweight = weights[0];
11176 
11177  /* taking these two weights together violates the knapsack => include into clique */
11178  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11179  {
11180  lastweight = weights[i];
11181  ++ncliquevars;
11182  }
11183 
11184  if( ncliquevars > 1 )
11185  {
11186  SCIP_Longint compareweight;
11187  SCIP_VAR** cliquevars;
11188  int compareweightidx;
11189  int minclqsize;
11190  int nnzadded;
11191 
11192  /* add the clique to the clique table */
11193  SCIPdebug( printClique(items, ncliquevars) );
11194  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11195 
11196  if( *cutoff )
11197  return SCIP_OKAY;
11198 
11199  *nbdchgs += thisnbdchgs;
11200  nnzadded = ncliquevars;
11201 
11202  /* 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)*/
11203  if( ncliquevars == nitems )
11204  return SCIP_OKAY;
11205 
11206  /* copy items in order into buffer array and deduce more cliques */
11207  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11208 
11209  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11210  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11211  compareweightidx = ncliquevars - 2;
11212  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11213 
11214  /* determine minimum clique size for the following loop */
11215  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11216  minclqsize = MAX(minclqsize, 2);
11217 
11218  /* loop over the remaining variables and the larger items of the first clique until we
11219  * find another clique or reach the size limit */
11220  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11221  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11222  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11223  )
11224  {
11225  compareweight = weights[compareweightidx];
11226  assert(compareweight > 0);
11227 
11228  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11229  if( compareweight + weights[i] > capacity )
11230  {
11231  assert(compareweightidx == ncliquevars -2);
11232  cliquevars[ncliquevars - 1] = items[i];
11233  SCIPdebug( printClique(cliquevars, ncliquevars) );
11234  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11235 
11236  nnzadded += ncliquevars;
11237 
11238  /* stop when there is a cutoff */
11239  if( ! (*cutoff) )
11240  *nbdchgs += thisnbdchgs;
11241 
11242  /* go to next smaller item */
11243  ++i;
11244  }
11245  else
11246  {
11247  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11248  compareweightidx--;
11249  ncliquevars --;
11250  }
11251  }
11252 
11253  SCIPfreeBufferArray(scip, &cliquevars);
11254  }
11255 
11256  return SCIP_OKAY;
11257 }
11258 
11259 /** adds cliques of the knapsack constraint to the global clique table */
11260 static
11262  SCIP*const scip, /**< SCIP data structure */
11263  SCIP_CONS*const cons, /**< knapsack constraint */
11264  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11265  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11266  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11267  )
11268 {
11269  SCIP_CONSDATA* consdata;
11270  SCIP_CONSHDLRDATA* conshdlrdata;
11271  int i;
11272  SCIP_Longint minactduetonegcliques;
11273  SCIP_Longint freecapacity;
11274  int nnegcliques;
11275  int cliquenum;
11276  SCIP_VAR** poscliquevars;
11277  SCIP_Longint* gainweights;
11278  int nposcliquevars;
11279  SCIP_Longint* secondmaxweights;
11280  int nvars;
11281 
11282  assert(scip != NULL);
11283  assert(cons != NULL);
11284  assert(cutoff != NULL);
11285  assert(nbdchgs != NULL);
11286 
11287  *cutoff = FALSE;
11288 
11289  consdata = SCIPconsGetData(cons);
11290  assert(consdata != NULL);
11291 
11292  nvars = consdata->nvars;
11293 
11294  /* check whether the cliques have already been added */
11295  if( consdata->cliquesadded || nvars == 0 )
11296  return SCIP_OKAY;
11297 
11298  /* make sure, the items are merged */
11299  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11300  if( *cutoff )
11301  return SCIP_OKAY;
11302 
11303  /* make sure, the items are sorted by non-increasing weight */
11304  sortItems(consdata);
11305 
11306  assert(consdata->merged);
11307 
11308  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11309  assert(conshdlrdata != NULL);
11310 
11311  /* calculate a clique partition */
11312  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11313  nnegcliques = consdata->nnegcliques;
11314  assert(nnegcliques <= nvars);
11315 
11316  /* get temporary memory */
11317  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11318  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11319  BMSclearMemoryArray(gainweights, nvars);
11320  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11321  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11322 
11323  minactduetonegcliques = 0;
11324 
11325  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11326  if( nnegcliques < nvars )
11327  {
11328  nnegcliques = 0;
11329 
11330  for( i = 0; i < nvars; ++i )
11331  {
11332  SCIP_Longint weight;
11333 
11334  cliquenum = consdata->negcliquepartition[i];
11335  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11336 
11337  weight = consdata->weights[i];
11338  assert(weight > 0);
11339 
11340  if( cliquenum == nnegcliques )
11341  nnegcliques++;
11342  else
11343  {
11344  minactduetonegcliques += weight;
11345  if( secondmaxweights[cliquenum] == 0 )
11346  secondmaxweights[cliquenum] = weight;
11347  }
11348  }
11349  }
11350 
11351  /* add cliques, using negated cliques information */
11352  if( minactduetonegcliques > 0 )
11353  {
11354  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11355  freecapacity = consdata->capacity - minactduetonegcliques;
11356 
11357  SCIPdebugPrintCons(scip, cons, NULL);
11358  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",
11359  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11360 
11361  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11362  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11363 
11364  if( *cutoff )
11365  goto TERMINATE;
11366 
11367  nposcliquevars = 0;
11368 
11369  for( i = nvars - 1; i >= 0; --i )
11370  {
11371  /* if we would take the biggest weight instead of the second biggest */
11372  cliquenum = consdata->negcliquepartition[i];
11373  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11374  {
11375  poscliquevars[nposcliquevars] = consdata->vars[i];
11376  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11377  ++nposcliquevars;
11378  }
11379  }
11380 
11381  /* use the gain weights and free capacity to derive greedily cliques */
11382  if( nposcliquevars > 1 )
11383  {
11384  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11385 
11386  if( *cutoff )
11387  goto TERMINATE;
11388  }
11389  }
11390 
11391  /* build cliques by using the items with the maximal weights */
11392  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11393 
11394  TERMINATE:
11395  /* free temporary memory and mark the constraint */
11396  SCIPfreeBufferArray(scip, &secondmaxweights);
11397  SCIPfreeBufferArray(scip, &gainweights);
11398  SCIPfreeBufferArray(scip, &poscliquevars);
11399  consdata->cliquesadded = TRUE;
11400 
11401  return SCIP_OKAY;
11402 }
11403 
11404 
11405 /** gets the key of the given element */
11406 static
11407 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11408 { /*lint --e{715}*/
11409  /* the key is the element itself */
11410  return elem;
11411 }
11412 
11413 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11414  * same coefficients
11415  */
11416 static
11417 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11418 {
11419 #ifndef NDEBUG
11420  SCIP* scip;
11421 #endif
11422  SCIP_CONSDATA* consdata1;
11423  SCIP_CONSDATA* consdata2;
11424  int i;
11426  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11427  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11428  assert(consdata1->sorted);
11429  assert(consdata2->sorted);
11430 #ifndef NDEBUG
11431  scip = (SCIP*)userptr;
11432  assert(scip != NULL);
11433 #endif
11434 
11435  /* checks trivial case */
11436  if( consdata1->nvars != consdata2->nvars )
11437  return FALSE;
11438 
11439  for( i = consdata1->nvars - 1; i >= 0; --i )
11440  {
11441  /* tests if variables are equal */
11442  if( consdata1->vars[i] != consdata2->vars[i] )
11443  {
11444  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11445  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11446  return FALSE;
11447  }
11448  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11449 
11450  /* tests if weights are equal too */
11451  if( consdata1->weights[i] != consdata2->weights[i] )
11452  return FALSE;
11453  }
11454 
11455  return TRUE;
11456 }
11457 
11458 /** returns the hash value of the key */
11459 static
11460 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11461 {
11462 #ifndef NDEBUG
11463  SCIP* scip;
11464 #endif
11465  SCIP_CONSDATA* consdata;
11466  uint64_t firstweight;
11467  int minidx;
11468  int mididx;
11469  int maxidx;
11470 
11471  consdata = SCIPconsGetData((SCIP_CONS*)key);
11472  assert(consdata != NULL);
11473  assert(consdata->nvars > 0);
11474 
11475 #ifndef NDEBUG
11476  scip = (SCIP*)userptr;
11477  assert(scip != NULL);
11478 #endif
11479 
11480  /* sorts the constraints */
11481  sortItems(consdata);
11482 
11483  minidx = SCIPvarGetIndex(consdata->vars[0]);
11484  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11485  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11486  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11487 
11488  /* hash value depends on vectors of variable indices */
11489  firstweight = (uint64_t)consdata->weights[0];
11490  return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11491 }
11492 
11493 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11494  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11495  */
11496 static
11498  SCIP* scip, /**< SCIP data structure */
11499  BMS_BLKMEM* blkmem, /**< block memory */
11500  SCIP_CONS** conss, /**< constraint set */
11501  int nconss, /**< number of constraints in constraint set */
11502  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11503  int* ndelconss /**< pointer to count number of deleted constraints */
11504  )
11506  SCIP_HASHTABLE* hashtable;
11507  int hashtablesize;
11508  int c;
11509 
11510  assert(scip != NULL);
11511  assert(blkmem != NULL);
11512  assert(conss != NULL);
11513  assert(ndelconss != NULL);
11514 
11515  /* create a hash table for the constraint set */
11516  hashtablesize = nconss;
11517  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11518  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11519  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11520 
11521  /* check all constraints in the given set for redundancy */
11522  for( c = nconss - 1; c >= 0; --c )
11523  {
11524  SCIP_CONS* cons0;
11525  SCIP_CONS* cons1;
11526  SCIP_CONSDATA* consdata0;
11527 
11528  cons0 = conss[c];
11529 
11530  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11531  continue;
11532 
11533  consdata0 = SCIPconsGetData(cons0);
11534  assert(consdata0 != NULL);
11535  if( consdata0->nvars == 0 )
11536  {
11537  if( consdata0->capacity < 0 )
11538  {
11539  *cutoff = TRUE;
11540  goto TERMINATE;
11541  }
11542  else
11543  {
11544  SCIP_CALL( SCIPdelCons(scip, cons0) );
11545  ++(*ndelconss);
11546  continue;
11547  }
11548  }
11549 
11550  /* get constraint from current hash table with same variables and same weights as cons0 */
11551  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11552 
11553  if( cons1 != NULL )
11554  {
11555  SCIP_CONS* consstay;
11556  SCIP_CONS* consdel;
11557  SCIP_CONSDATA* consdata1;
11558 
11559  assert(SCIPconsIsActive(cons1));
11560  assert(!SCIPconsIsModifiable(cons1));
11561 
11562  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11563  * delete old constraints afterwards
11564  */
11565  consdata1 = SCIPconsGetData(cons1);
11566 
11567  assert(consdata1 != NULL);
11568  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11569 
11570  assert(consdata0->sorted && consdata1->sorted);
11571  assert(consdata0->vars[0] == consdata1->vars[0]);
11572  assert(consdata0->weights[0] == consdata1->weights[0]);
11573 
11574  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11575  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11576 
11577  /* check which constraint has to stay; */
11578  if( consdata0->capacity < consdata1->capacity )
11579  {
11580  consstay = cons0;
11581  consdel = cons1;
11582 
11583  /* exchange consdel with consstay in hashtable */
11584  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11585  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11586  }
11587  else
11588  {
11589  consstay = cons1;
11590  consdel = cons0;
11591  }
11592 
11593  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11594  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11595 
11596  /* delete consdel */
11597  SCIP_CALL( SCIPdelCons(scip, consdel) );
11598  ++(*ndelconss);
11599 
11600  assert(SCIPconsIsActive(consstay));
11601  }
11602  else
11603  {
11604  /* no such constraint in current hash table: insert cons0 into hash table */
11605  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11606  }
11607  }
11608 
11609  TERMINATE:
11610  /* free hash table */
11611  SCIPhashtableFree(&hashtable);
11612 
11613  return SCIP_OKAY;
11614 }
11615 
11616 
11617 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11618  * and removes or changes constraint accordingly
11619  */
11620 static
11622  SCIP* scip, /**< SCIP data structure */
11623  SCIP_CONS** conss, /**< constraint set */
11624  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11625  int chkind, /**< index of constraint to check against all prior indices upto startind */
11626  int* ndelconss /**< pointer to count number of deleted constraints */
11627  )
11628 {
11629  SCIP_CONS* cons0;
11630  SCIP_CONSDATA* consdata0;
11631  int c;
11632 
11633  assert(scip != NULL);
11634  assert(conss != NULL);
11635  assert(firstchange <= chkind);
11636  assert(ndelconss != NULL);
11637 
11638  /* get the constraint to be checked against all prior constraints */
11639  cons0 = conss[chkind];
11640  assert(cons0 != NULL);
11641  assert(SCIPconsIsActive(cons0));
11642  assert(!SCIPconsIsModifiable(cons0));
11643 
11644  consdata0 = SCIPconsGetData(cons0);
11645  assert(consdata0 != NULL);
11646  assert(consdata0->nvars >= 1);
11647  assert(consdata0->merged);
11648 
11649  /* sort the constraint */
11650  sortItems(consdata0);
11651 
11652  /* see #2970 */
11653  if( consdata0->capacity == 0 )
11654  return SCIP_OKAY;
11655 
11656  /* check constraint against all prior constraints */
11657  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11658  {
11659  SCIP_CONS* cons1;
11660  SCIP_CONSDATA* consdata1;
11661  SCIP_Bool iscons0incons1contained;
11662  SCIP_Bool iscons1incons0contained;
11663  SCIP_Real quotient;
11664  int v;
11665  int v0;
11666  int v1;
11667 
11668  cons1 = conss[c];
11669  assert(cons1 != NULL);
11670  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11671  continue;
11672 
11673  consdata1 = SCIPconsGetData(cons1);
11674  assert(consdata1 != NULL);
11675 
11676  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11677  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11678  continue;
11679 
11680  assert(consdata1->nvars >= 1);
11681  assert(consdata1->merged);
11682 
11683  /* sort the constraint */
11684  sortItems(consdata1);
11685 
11686  /* see #2970 */
11687  if( consdata1->capacity == 0 )
11688  continue;
11689 
11690  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11691 
11692  if( consdata0->nvars > consdata1->nvars )
11693  {
11694  iscons0incons1contained = FALSE;
11695  iscons1incons0contained = TRUE;
11696  v = consdata1->nvars - 1;
11697  }
11698  else if( consdata0->nvars < consdata1->nvars )
11699  {
11700  iscons0incons1contained = TRUE;
11701  iscons1incons0contained = FALSE;
11702  v = consdata0->nvars - 1;
11703  }
11704  else
11705  {
11706  iscons0incons1contained = TRUE;
11707  iscons1incons0contained = TRUE;
11708  v = consdata0->nvars - 1;
11709  }
11710 
11711  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11712 
11713  /* check consdata0 against consdata1:
11714  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11715  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11716  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11717  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11718  */
11719  v0 = consdata0->nvars - 1;
11720  v1 = consdata1->nvars - 1;
11721 
11722  while( v >= 0 )
11723  {
11724  assert(iscons0incons1contained || iscons1incons0contained);
11725 
11726  /* now there are more variables in cons1 left */
11727  if( v1 > v0 )
11728  {
11729  iscons1incons0contained = FALSE;
11730  if( !iscons0incons1contained )
11731  break;
11732  }
11733  /* now there are more variables in cons0 left */
11734  else if( v1 < v0 )
11735  {
11736  iscons0incons1contained = FALSE;
11737  if( !iscons1incons0contained )
11738  break;
11739  }
11740 
11741  assert(v == v0 || v == v1);
11742  assert(v0 >= 0);
11743  assert(v1 >= 0);
11744 
11745  /* both variables are the same */
11746  if( consdata0->vars[v0] == consdata1->vars[v1] )
11747  {
11748  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11749  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11750  {
11751  iscons1incons0contained = FALSE;
11752  if( !iscons0incons1contained )
11753  break;
11754  }
11755  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11756  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11757  {
11758  iscons0incons1contained = FALSE;
11759  if( !iscons1incons0contained )
11760  break;
11761  }
11762  --v0;
11763  --v1;
11764  --v;
11765  }
11766  else
11767  {
11768  /* both constraints have a variables which is not part of the other constraint, so stop */
11769  if( iscons0incons1contained && iscons1incons0contained )
11770  {
11771  iscons0incons1contained = FALSE;
11772  iscons1incons0contained = FALSE;
11773  break;
11774  }
11775  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11776  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11777  /* continue to the next variable */
11778  if( iscons0incons1contained )
11779  --v1;
11780  else
11781  --v0;
11782  }
11783  }
11784  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11785  * other
11786  */
11787  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11788 
11789  if( iscons1incons0contained )
11790  {
11791  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11792  SCIPdebugPrintCons(scip, cons1, NULL);
11793 
11794  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11795  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11796 
11797  SCIP_CALL( SCIPdelCons(scip, cons1) );
11798  ++(*ndelconss);
11799  }
11800  else if( iscons0incons1contained )
11801  {
11802  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11803  SCIPdebugPrintCons(scip, cons0, NULL);
11804 
11805  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11806  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11807 
11808  SCIP_CALL( SCIPdelCons(scip, cons0) );
11809  ++(*ndelconss);
11810  break;
11811  }
11812  }
11813 
11814  return SCIP_OKAY;
11815 }
11816 
11817 /** helper function to enforce constraints */
11818 static
11820  SCIP* scip, /**< SCIP data structure */
11821  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11822  SCIP_CONS** conss, /**< constraints to process */
11823  int nconss, /**< number of constraints */
11824  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11825  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11826  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11827  )
11828 {
11829  SCIP_CONSHDLRDATA* conshdlrdata;
11830  SCIP_Bool violated;
11831  SCIP_Bool cutoff = FALSE;
11832  int maxncuts;
11833  int ncuts = 0;
11834  int i;
11835 
11836  *result = SCIP_FEASIBLE;
11837 
11838  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11839  sol == NULL ? "LP" : "relaxation");
11840 
11841  /* get maximal number of cuts per round */
11842  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11843  assert(conshdlrdata != NULL);
11844  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11845 
11846  /* search for violated useful knapsack constraints */
11847  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11848  {
11849  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11850  if( violated )
11851  {
11852  /* add knapsack constraint as LP row to the relaxation */
11853  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11854  ncuts++;
11855  }
11856  }
11857 
11858  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11859  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11860  {
11861  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11862  if( violated )
11863  {
11864  /* add knapsack constraint as LP row to the relaxation */
11865  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11866  ncuts++;
11867  }
11868  }
11869 
11870  /* adjust the result code */
11871  if ( cutoff )
11872  *result = SCIP_CUTOFF;
11873  else if ( ncuts > 0 )
11874  *result = SCIP_SEPARATED;
11875 
11876  return SCIP_OKAY;
11877 }
11878 
11879 /*
11880  * Linear constraint upgrading
11881  */
11882 
11883 /** creates and captures a knapsack constraint out of a linear inequality */
11884 static
11886  SCIP* scip, /**< SCIP data structure */
11887  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11888  const char* name, /**< name of constraint */
11889  int nvars, /**< number of variables in the constraint */
11890  SCIP_VAR** vars, /**< array with variables of constraint entries */
11891  SCIP_Real* vals, /**< array with inequality coefficients */
11892  SCIP_Real lhs, /**< left hand side of inequality */
11893  SCIP_Real rhs, /**< right hand side of inequality */
11894  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11895  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11896  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11897  * Usually set to TRUE. */
11898  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11899  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11900  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11901  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11902  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11903  * Usually set to TRUE. */
11904  SCIP_Bool local, /**< is constraint only valid locally?
11905  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11906  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11907  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11908  * adds coefficients to this constraint. */
11909  SCIP_Bool dynamic, /**< is constraint subject to aging?
11910  * Usually set to FALSE. Set to TRUE for own cuts which
11911  * are separated as constraints. */
11912  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11913  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11914  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11915  * if it may be moved to a more global node?
11916  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11917  )
11918 {
11919  SCIP_VAR** transvars;
11920  SCIP_Longint* weights;
11921  SCIP_Longint capacity;
11922  SCIP_Longint weight;
11923  int mult;
11924  int v;
11925 
11926  assert(nvars == 0 || vars != NULL);
11927  assert(nvars == 0 || vals != NULL);
11928  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11929 
11930  /* get temporary memory */
11931  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11932  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11933 
11934  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11935  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11936  */
11937  if( SCIPisInfinity(scip, rhs) )
11938  {
11939  mult = -1;
11940  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11941  }
11942  else
11943  {
11944  mult = +1;
11945  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11946  }
11947 
11948  /* negate positive or negative variables */
11949  for( v = 0; v < nvars; ++v )
11950  {
11951  assert(SCIPisFeasIntegral(scip, vals[v]));
11952  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11953  if( weight > 0 )
11954  {
11955  transvars[v] = vars[v];
11956  weights[v] = weight;
11957  }
11958  else
11959  {
11960  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11961  weights[v] = -weight; /*lint !e2704*/
11962  capacity -= weight;
11963  }
11964  assert(transvars[v] != NULL);
11965  }
11966 
11967  /* create the constraint */
11968  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11969  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11970 
11971  /* free temporary memory */
11972  SCIPfreeBufferArray(scip, &weights);
11973  SCIPfreeBufferArray(scip, &transvars);
11974 
11975  return SCIP_OKAY;
11976 }
11977 
11978 /** tries to upgrade a linear constraint into a knapsack constraint */
11979 static
11980 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11981 { /*lint --e{715}*/
11982  SCIP_Bool upgrade;
11983 
11984  assert(upgdcons != NULL);
11985 
11986  /* check, if linear constraint can be upgraded to a knapsack constraint
11987  * - all variables must be binary
11988  * - all coefficients must be integral
11989  * - exactly one of the sides must be infinite
11990  * note that this includes the case of negative capacity, which has been
11991  * observed to occur, e.g., when upgrading a conflict constraint
11992  */
11993  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11994  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11995  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11996 
11997  if( upgrade )
11998  {
11999  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12000 
12001  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12002  assert(!SCIPconsIsModifiable(cons));
12003  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12008  }
12009 
12010  return SCIP_OKAY;
12011 }
12012 
12013 /** adds symmetry information of constraint to a symmetry detection graph */
12014 static
12016  SCIP* scip, /**< SCIP pointer */
12017  SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
12018  SCIP_CONS* cons, /**< constraint */
12019  SYM_GRAPH* graph, /**< symmetry detection graph */
12020  SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
12021  )
12022 {
12023  SCIP_CONSDATA* consdata;
12024  SCIP_VAR** vars;
12025  SCIP_Real* vals;
12026  SCIP_Real constant = 0.0;
12027  SCIP_Real rhs;
12028  int nlocvars;
12029  int nvars;
12030  int i;
12031 
12032  assert(scip != NULL);
12033  assert(cons != NULL);
12034  assert(graph != NULL);
12035  assert(success != NULL);
12036 
12037  consdata = SCIPconsGetData(cons);
12038  assert(consdata != NULL);
12039  assert(graph != NULL);
12040 
12041  /* get active variables of the constraint */
12042  nvars = SCIPgetNVars(scip);
12043  nlocvars = consdata->nvars;
12044 
12045  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
12046  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
12047 
12048  for( i = 0; i < consdata->nvars; ++i )
12049  {
12050  vars[i] = consdata->vars[i];
12051  vals[i] = (SCIP_Real) consdata->weights[i];
12052  }
12053 
12054  SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
12055  rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
12056 
12057  SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars,
12058  cons, -SCIPinfinity(scip), rhs, success) );
12059 
12060  SCIPfreeBufferArray(scip, &vals);
12061  SCIPfreeBufferArray(scip, &vars);
12062 
12063  return SCIP_OKAY;
12064 }
12065 
12066 /*
12067  * Callback methods of constraint handler
12068  */
12069 
12070 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12071 /**! [SnippetConsCopyKnapsack] */
12072 static
12073 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12074 { /*lint --e{715}*/
12075  assert(scip != NULL);
12076  assert(conshdlr != NULL);
12077  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12078 
12079  /* call inclusion method of constraint handler */
12082  *valid = TRUE;
12083 
12084  return SCIP_OKAY;
12085 }
12086 /**! [SnippetConsCopyKnapsack] */
12087 
12088 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12089 /**! [SnippetConsFreeKnapsack] */
12090 static
12091 SCIP_DECL_CONSFREE(consFreeKnapsack)
12092 { /*lint --e{715}*/
12093  SCIP_CONSHDLRDATA* conshdlrdata;
12094 
12095  /* free constraint handler data */
12096  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12097  assert(conshdlrdata != NULL);
12098 
12099  SCIPfreeBlockMemory(scip, &conshdlrdata);
12100 
12101  SCIPconshdlrSetData(conshdlr, NULL);
12102 
12103  return SCIP_OKAY;
12104 }
12105 /**! [SnippetConsFreeKnapsack] */
12106 
12107 
12108 /** initialization method of constraint handler (called after problem was transformed) */
12109 static
12110 SCIP_DECL_CONSINIT(consInitKnapsack)
12111 { /*lint --e{715}*/
12112  SCIP_CONSHDLRDATA* conshdlrdata;
12113  int nvars;
12114 
12115  assert( scip != NULL );
12116  assert( conshdlr != NULL );
12117 
12118  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12119  assert(conshdlrdata != NULL);
12120 
12121  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12122  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12123 
12124  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12125  conshdlrdata->reals1size = nvars;
12126 
12127  return SCIP_OKAY;
12128 }
12129 
12130 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12131 static
12132 SCIP_DECL_CONSEXIT(consExitKnapsack)
12133 { /*lint --e{715}*/
12134  SCIP_CONSHDLRDATA* conshdlrdata;
12135 
12136  assert( scip != NULL );
12137  assert( conshdlr != NULL );
12138 
12139  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12140  assert(conshdlrdata != NULL);
12141 
12142  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12143  conshdlrdata->reals1size = 0;
12144 
12145  return SCIP_OKAY;
12146 }
12147 
12148 
12149 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12150 static
12151 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12152 { /*lint --e{715}*/
12153  SCIP_CONSHDLRDATA* conshdlrdata;
12154  int nvars;
12155 
12156  assert(scip != NULL);
12157  assert(conshdlr != NULL);
12158  assert(nconss == 0 || conss != NULL);
12160  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12161  assert(conshdlrdata != NULL);
12162 
12163  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12164  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12165 
12166  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12167  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12168  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12169  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12170  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12171  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12172  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12173  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12174 
12175  conshdlrdata->ints1size = nvars;
12176  conshdlrdata->ints2size = nvars;
12177  conshdlrdata->longints1size = nvars;
12178  conshdlrdata->longints2size = nvars;
12179  conshdlrdata->bools1size = nvars;
12180  conshdlrdata->bools2size = nvars;
12181  conshdlrdata->bools3size = nvars;
12182  conshdlrdata->bools4size = nvars;
12183 
12184 #ifdef WITH_CARDINALITY_UPGRADE
12185  conshdlrdata->upgradedcard = FALSE;
12186 #endif
12187 
12188  return SCIP_OKAY;
12189 }
12190 
12191 
12192 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12193 static
12194 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12195 { /*lint --e{715}*/
12196  SCIP_CONSHDLRDATA* conshdlrdata;
12197  int c;
12198 
12199  assert(scip != NULL);
12200  assert(conshdlr != NULL);
12201 
12202  for( c = 0; c < nconss; ++c )
12203  {
12204  if( !SCIPconsIsDeleted(conss[c]) )
12205  {
12206  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12207  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12208  }
12209  }
12210 
12211  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12212  assert(conshdlrdata != NULL);
12213 
12214  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12215  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12216  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12217  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12218  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12219  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12220  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12221  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12222 
12223  conshdlrdata->ints1size = 0;
12224  conshdlrdata->ints2size = 0;
12225  conshdlrdata->longints1size = 0;
12226  conshdlrdata->longints2size = 0;
12227  conshdlrdata->bools1size = 0;
12228  conshdlrdata->bools2size = 0;
12229  conshdlrdata->bools3size = 0;
12230  conshdlrdata->bools4size = 0;
12231 
12232  return SCIP_OKAY;
12233 }
12234 
12235 /** solving process initialization method of constraint handler */
12236 static
12237 SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12238 { /*lint --e{715}*/
12239  /* add nlrow representation to NLP, if NLP had been constructed */
12240  if( SCIPisNLPConstructed(scip) )
12241  {
12242  int c;
12243  for( c = 0; c < nconss; ++c )
12244  {
12245  SCIP_CALL( addNlrow(scip, conss[c]) );
12246  }
12247  }
12248 
12249  return SCIP_OKAY;
12250 }
12251 
12252 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12253 static
12254 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12255 { /*lint --e{715}*/
12256  SCIP_CONSDATA* consdata;
12257  int c;
12258 
12259  assert( scip != NULL );
12260 
12261  /* release the rows and nlrows of all constraints */
12262  for( c = 0; c < nconss; ++c )
12263  {
12264  consdata = SCIPconsGetData(conss[c]);
12265  assert(consdata != NULL);
12266 
12267  if( consdata->row != NULL )
12268  {
12269  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12270  }
12271 
12272  if( consdata->nlrow != NULL )
12273  {
12274  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12275  }
12276  }
12277 
12278  return SCIP_OKAY;
12279 }
12280 
12281 /** frees specific constraint data */
12282 static
12283 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12284 { /*lint --e{715}*/
12285  SCIP_CONSHDLRDATA* conshdlrdata;
12286 
12287  assert(conshdlr != NULL);
12288  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12289 
12290  /* get event handler */
12291  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12292  assert(conshdlrdata != NULL);
12293  assert(conshdlrdata->eventhdlr != NULL);
12294 
12295  /* free knapsack constraint */
12296  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12297 
12298  return SCIP_OKAY;
12299 }
12300 
12301 /** transforms constraint data into data belonging to the transformed problem */
12302 /**! [SnippetConsTransKnapsack]*/
12303 static
12304 SCIP_DECL_CONSTRANS(consTransKnapsack)
12305 { /*lint --e{715}*/
12306  SCIP_CONSHDLRDATA* conshdlrdata;
12307  SCIP_CONSDATA* sourcedata;
12308  SCIP_CONSDATA* targetdata;
12309 
12310  assert(conshdlr != NULL);
12311  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12313  assert(sourcecons != NULL);
12314  assert(targetcons != NULL);
12315 
12316  sourcedata = SCIPconsGetData(sourcecons);
12317  assert(sourcedata != NULL);
12318  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12319 
12320  /* get event handler */
12321  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12322  assert(conshdlrdata != NULL);
12323  assert(conshdlrdata->eventhdlr != NULL);
12324 
12325  /* create target constraint data */
12326  SCIP_CALL( consdataCreate(scip, &targetdata,
12327  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12328 
12329  /* create target constraint */
12330  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12331  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12332  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12333  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12334  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12335 
12336  /* catch events for variables */
12337  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12338 
12339  return SCIP_OKAY;
12340 }
12341 /**! [SnippetConsTransKnapsack]*/
12342 
12343 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12344 static
12345 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12346 { /*lint --e{715}*/
12347  int i;
12348 
12349  *infeasible = FALSE;
12350 
12351  for( i = 0; i < nconss && !(*infeasible); i++ )
12352  {
12353  assert(SCIPconsIsInitial(conss[i]));
12354  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12355  }
12356 
12357  return SCIP_OKAY;
12358 }
12359 
12360 /** separation method of constraint handler for LP solutions */
12361 static
12362 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12363 { /*lint --e{715}*/
12364  SCIP_CONSHDLRDATA* conshdlrdata;
12365  SCIP_Bool sepacardinality;
12366  SCIP_Bool cutoff;
12367 
12368  SCIP_Real loclowerbound;
12369  SCIP_Real glblowerbound;
12370  SCIP_Real cutoffbound;
12371  SCIP_Real maxbound;
12372 
12373  int depth;
12374  int nrounds;
12375  int sepafreq;
12376  int sepacardfreq;
12377  int ncuts;
12378  int maxsepacuts;
12379  int i;
12380 
12381  *result = SCIP_DIDNOTRUN;
12382 
12383  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12384  assert(conshdlrdata != NULL);
12385 
12386  depth = SCIPgetDepth(scip);
12387  nrounds = SCIPgetNSepaRounds(scip);
12388 
12389  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12390  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12391 
12392  /* only call the separator a given number of times at each node */
12393  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12394  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12395  return SCIP_OKAY;
12396 
12397  /* check, if we should additionally separate knapsack cuts */
12398  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12399  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12400  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12401  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12402 
12403  /* check dual bound to see if we want to produce knapsack cuts at this node */
12404  loclowerbound = SCIPgetLocalLowerbound(scip);
12405  glblowerbound = SCIPgetLowerbound(scip);
12406  cutoffbound = SCIPgetCutoffbound(scip);
12407  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12408  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12409  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12410 
12411  /* get the maximal number of cuts allowed in a separation round */
12412  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12413 
12414  *result = SCIP_DIDNOTFIND;
12415  ncuts = 0;
12416  cutoff = FALSE;
12417 
12418  /* separate useful constraints */
12419  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12420  {
12421  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12422  }
12423 
12424  /* adjust return value */
12425  if ( cutoff )
12426  *result = SCIP_CUTOFF;
12427  else if ( ncuts > 0 )
12428  *result = SCIP_SEPARATED;
12429 
12430  return SCIP_OKAY;
12431 }
12432 
12433 
12434 /** separation method of constraint handler for arbitrary primal solutions */
12435 static
12436 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12437 { /*lint --e{715}*/
12438  SCIP_CONSHDLRDATA* conshdlrdata;
12439  SCIP_Bool sepacardinality;
12440  SCIP_Bool cutoff;
12441 
12442  int depth;
12443  int nrounds;
12444  int sepafreq;
12445  int sepacardfreq;
12446  int ncuts;
12447  int maxsepacuts;
12448  int i;
12449 
12450  *result = SCIP_DIDNOTRUN;
12451 
12452  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12453  assert(conshdlrdata != NULL);
12454 
12455  depth = SCIPgetDepth(scip);
12456  nrounds = SCIPgetNSepaRounds(scip);
12457 
12458  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12459  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12460 
12461  /* only call the separator a given number of times at each node */
12462  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12463  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12464  return SCIP_OKAY;
12465 
12466  /* check, if we should additionally separate knapsack cuts */
12467  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12468  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12469  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12470  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12471 
12472  /* get the maximal number of cuts allowed in a separation round */
12473  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12474 
12475  *result = SCIP_DIDNOTFIND;
12476  ncuts = 0;
12477  cutoff = FALSE;
12478 
12479  /* separate useful constraints */
12480  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12481  {
12482  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12483  }
12484 
12485  /* adjust return value */
12486  if ( cutoff )
12487  *result = SCIP_CUTOFF;
12488  else if( ncuts > 0 )
12489  *result = SCIP_SEPARATED;
12490 
12491  return SCIP_OKAY;
12492 }
12493 
12494 /** constraint enforcing method of constraint handler for LP solutions */
12495 static
12496 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12497 { /*lint --e{715}*/
12498  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12499 
12500  return SCIP_OKAY;
12501 }
12502 
12503 /** constraint enforcing method of constraint handler for relaxation solutions */
12504 static
12505 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12506 { /*lint --e{715}*/
12507  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12508 
12509  return SCIP_OKAY;
12510 }
12511 
12512 /** constraint enforcing method of constraint handler for pseudo solutions */
12513 static
12514 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12515 { /*lint --e{715}*/
12516  SCIP_Bool violated;
12517  int i;
12518 
12519  for( i = 0; i < nconss; i++ )
12520  {
12521  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12522  if( violated )
12523  {
12524  *result = SCIP_INFEASIBLE;
12525  return SCIP_OKAY;
12526  }
12527  }
12528  *result = SCIP_FEASIBLE;
12529 
12530  return SCIP_OKAY;
12531 }
12532 
12533 /** feasibility check method of constraint handler for integral solutions */
12534 static
12535 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12536 { /*lint --e{715}*/
12537  SCIP_Bool violated;
12538  int i;
12539 
12540  *result = SCIP_FEASIBLE;
12541 
12542  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12543  {
12544  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12545  if( violated )
12546  *result = SCIP_INFEASIBLE;
12547  }
12548 
12549  return SCIP_OKAY;
12550 }
12551 
12552 /** domain propagation method of constraint handler */
12553 static
12554 SCIP_DECL_CONSPROP(consPropKnapsack)
12555 { /*lint --e{715}*/
12556  SCIP_CONSHDLRDATA* conshdlrdata;
12557  SCIP_Bool cutoff;
12558  SCIP_Bool redundant;
12559  SCIP_Bool inpresolve;
12560  int nfixedvars;
12561  int i;
12563  cutoff = FALSE;
12564  nfixedvars = 0;
12565 
12566  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12567  assert(conshdlrdata != NULL);
12568 
12569  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12570  assert(!inpresolve || SCIPinProbing(scip));
12571 
12572  /* process useful constraints */
12573  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12574  {
12575  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12576  * otherwise the multi-aggregation should be resolved
12577  */
12578  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12579  continue;
12580 #ifndef NDEBUG
12581  else
12582  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12583 #endif
12584 
12585  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12586 
12587  /* unmark the constraint to be propagated */
12588  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12589  }
12590 
12591  /* adjust result code */
12592  if( cutoff )
12593  *result = SCIP_CUTOFF;
12594  else if( nfixedvars > 0 )
12595  *result = SCIP_REDUCEDDOM;
12596  else
12597  *result = SCIP_DIDNOTFIND;
12598 
12599  return SCIP_OKAY; /*lint !e438*/
12600 }
12601 
12602 /** presolving method of constraint handler */
12603 static
12604 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12605 { /*lint --e{574,715}*/
12606  SCIP_CONSHDLRDATA* conshdlrdata;
12607  SCIP_CONSDATA* consdata;
12608  SCIP_CONS* cons;
12609  SCIP_Bool cutoff;
12610  SCIP_Bool redundant;
12611  SCIP_Bool success;
12612  int oldnfixedvars;
12613  int oldnchgbds;
12614  int oldndelconss;
12615  int oldnaddconss;
12616  int oldnchgcoefs;
12617  int oldnchgsides;
12618  int firstchange;
12619  int c;
12620  SCIP_Bool newchanges;
12621 
12622  /* remember old preprocessing counters */
12623  cutoff = FALSE;
12624  oldnfixedvars = *nfixedvars;
12625  oldnchgbds = *nchgbds;
12626  oldndelconss = *ndelconss;
12627  oldnaddconss = *naddconss;
12628  oldnchgcoefs = *nchgcoefs;
12629  oldnchgsides = *nchgsides;
12630  firstchange = INT_MAX;
12631 
12632  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12633 
12634  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12635  assert(conshdlrdata != NULL);
12636 
12637  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12638  {
12639  int thisnfixedvars;
12640  int thisnchgbds;
12641 
12642  cons = conss[c];
12643  consdata = SCIPconsGetData(cons);
12644  assert(consdata != NULL);
12645 
12646  /* update data structures */
12647  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12648  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12649  {
12650  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12651  if( cutoff )
12652  break;
12653  }
12654 
12655  /* force presolving the constraint in the initial round */
12656  if( nrounds == 0 )
12657  consdata->presolvedtiming = 0;
12658  else if( consdata->presolvedtiming >= presoltiming )
12659  continue;
12660 
12661  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12662  SCIPdebugPrintCons(scip, cons, NULL);
12663  consdata->presolvedtiming = presoltiming;
12664 
12665  thisnfixedvars = *nfixedvars;
12666  thisnchgbds = *nchgbds;
12667 
12668  /* merge constraint, so propagation works better */
12669  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12670  if( cutoff )
12671  break;
12672 
12673  /* add cliques in the knapsack to the clique table */
12674  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12675  {
12676  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12677  if( cutoff )
12678  break;
12679  }
12680 
12681  /* propagate constraint */
12682  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12683  {
12684  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12685 
12686  if( cutoff )
12687  break;
12688  if( redundant )
12689  {
12690  (*ndelconss)++;
12691  continue;
12692  }
12693  }
12694 
12695  /* remove again all fixed variables, if further fixings were found */
12696  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12697  {
12698  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12699  if( cutoff )
12700  break;
12701 
12702  thisnfixedvars = *nfixedvars;
12703  }
12704 
12705  if( !SCIPconsIsModifiable(cons) )
12706  {
12707  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12708  if( consdata->weightsum <= consdata->capacity )
12709  {
12710  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12711  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12712  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12713  continue;
12714  }
12715 
12716  /* divide weights by their greatest common divisor */
12717  normalizeWeights(cons, nchgcoefs, nchgsides);
12718 
12719  /* try to simplify inequalities */
12720  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12721  {
12722  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12723  if( cutoff )
12724  break;
12725 
12726  if( SCIPconsIsDeleted(cons) )
12727  continue;
12728 
12729  /* remove again all fixed variables, if further fixings were found */
12730  if( *nfixedvars > thisnfixedvars )
12731  {
12732  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12733  if( cutoff )
12734  break;
12735  }
12736  }
12737 
12738  /* tighten capacity and weights */
12739  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12740  if( cutoff )
12741  break;
12742 
12743  if( SCIPconsIsActive(cons) )
12744  {
12745  if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12746  {
12747  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12748  * dual reduction
12749  */
12750  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12751  if( redundant )
12752  continue;
12753  }
12754 
12755  /* check if knapsack constraint is parallel to objective function */
12756  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12757  }
12758  }
12759  /* remember the first changed constraint to begin the next aggregation round with */
12760  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12761  firstchange = c;
12762  }
12763 
12764  /* preprocess pairs of knapsack constraints */
12765  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12766  {
12767  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12768  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12769  }
12770 
12771  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12772  success = TRUE;
12773  else
12774  success = FALSE;
12775 
12776  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12777  {
12778  SCIP_Longint npaircomparisons;
12779 
12780  npaircomparisons = 0;
12781  oldndelconss = *ndelconss;
12782  oldnchgsides = *nchgsides;
12783  oldnchgcoefs = *nchgcoefs;
12784 
12785  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12786  {
12787  cons = conss[c];
12788  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12789  continue;
12790 
12791  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12792 
12793  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12794 
12795  if( npaircomparisons > NMINCOMPARISONS )
12796  {
12797  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12798  success = TRUE;
12799  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12800  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12801  break;
12802  oldndelconss = *ndelconss;
12803  oldnchgsides = *nchgsides;
12804  oldnchgcoefs = *nchgcoefs;
12805  npaircomparisons = 0;
12806  }
12807  }
12808  }
12809 #ifdef WITH_CARDINALITY_UPGRADE
12810  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12811  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12812  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12813  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12814  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12815  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12816  * as well, we better keep this code disabled. */
12817  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12818  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12819  {
12820  SCIP_HASHMAP* varhash;
12821  SCIP_VAR** cardvars;
12822  SCIP_Real* cardweights;
12823  int noldupgdconss;
12824  int nscipvars;
12825  int makeupgrade;
12826 
12827  noldupgdconss = *nupgdconss;
12828  nscipvars = SCIPgetNVars(scip);
12829  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12830  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12831 
12832  /* set up hash map */
12833  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12834 
12835  /* We loop through all cardinality constraints twice:
12836  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12837  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12838  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12839  * - Second, upgrade knapsack constraints to cardinality constraints. */
12840  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12841  {
12842  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12843  {
12844  SCIP_CONS* cardcons;
12845  SCIP_VAR** vars;
12846  SCIP_Longint* weights;
12847  int nvars;
12848  int v;
12849 
12850  cons = conss[c];
12851  assert( cons != NULL );
12852  consdata = SCIPconsGetData(cons);
12853  assert( consdata != NULL );
12854 
12855  nvars = consdata->nvars;
12856  vars = consdata->vars;
12857  weights = consdata->weights;
12858 
12859  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12860  * - all variables must be binary (always true)
12861  * - all coefficients must be 1.0
12862  * - the right hand side must be smaller than nvars
12863  */
12864  if ( consdata->capacity >= nvars )
12865  continue;
12866 
12867  /* the weights are sorted: check first and last weight */
12868  assert( consdata->sorted );
12869  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12870  continue;
12871 
12872  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12873  for (v = 0; v < nvars; ++v)
12874  {
12875  SCIP_BOUNDTYPE* impltypes;
12876  SCIP_Real* implbounds;
12877  SCIP_VAR** implvars;
12878  SCIP_VAR* var;
12879  int nimpls;
12880  int j;
12881 
12882  var = consdata->vars[v];
12883  assert( var != NULL );
12884  assert( SCIPvarIsBinary(var) );
12885 
12886  /* ignore non-active variables */
12887  if ( ! SCIPvarIsActive(var) )
12888  break;
12889 
12890  /* be sure that implication variable has zero objective */
12891  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12892  break;
12893 
12894  nimpls = SCIPvarGetNImpls(var, FALSE);
12895  implvars = SCIPvarGetImplVars(var, FALSE);
12896  implbounds = SCIPvarGetImplBounds(var, FALSE);
12897  impltypes = SCIPvarGetImplTypes(var, FALSE);
12898 
12899  for (j = 0; j < nimpls; ++j)
12900  {
12901  /* be sure that continuous variable is fixed to 0 */
12902  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12903  continue;
12904 
12905  /* cannot currently deal with nonzero fixings */
12906  if ( ! SCIPisZero(scip, implbounds[j]) )
12907  continue;
12908 
12909  /* number of down locks should be one */
12910  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12911  continue;
12912 
12913  cardvars[v] = implvars[j];
12914  cardweights[v] = (SCIP_Real) v;
12915 
12916  break;
12917  }
12918 
12919  /* found no variable upper bound candidate -> exit */
12920  if ( j >= nimpls )
12921  break;
12922  }
12923 
12924  /* did not find fitting variable upper bound for some variable -> exit */
12925  if ( v < nvars )
12926  break;
12927 
12928  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12929  * in which the binary variable is involved in */
12930  if ( makeupgrade == 0 )
12931  {
12932  for (v = 0; v < nvars; ++v)
12933  {
12934  if ( SCIPhashmapExists(varhash, vars[v]) )
12935  {
12936  int image;
12937 
12938  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12939  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12940  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12941  }
12942  else
12943  {
12944  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12945  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12946  assert( SCIPhashmapExists(varhash, vars[v]) );
12947  }
12948  }
12949  }
12950  else
12951  {
12952  SCIP_CONS* origcons;
12953 
12954  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12955  * knapsack constraint coincides with the number of variable up locks */
12956  for (v = 0; v < nvars; ++v)
12957  {
12958  assert( SCIPhashmapExists(varhash, vars[v]) );
12959  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12960  break;
12961  }
12962  if ( v < nvars )
12963  break;
12964 
12965  /* store that we have upgraded */
12966  conshdlrdata->upgradedcard = TRUE;
12967 
12968  /* at this point we found suitable variable upper bounds */
12969  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12970 
12971  /* create cardinality constraint */
12972  assert( ! SCIPconsIsModifiable(cons) );
12973  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12977 #ifdef SCIP_DEBUG
12978  SCIPprintCons(scip, cons, NULL);
12979  SCIPinfoMessage(scip, NULL, "\n");
12980  SCIPprintCons(scip, cardcons, NULL);
12981  SCIPinfoMessage(scip, NULL, "\n");
12982 #endif
12983  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12984  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12985  ++(*nupgdconss);
12986 
12987  /* delete oknapsack constraint */
12988  SCIP_CALL( SCIPdelCons(scip, cons) );
12989  ++(*ndelconss);
12990 
12991  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12992  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12993  * although the cardinality constraint is satisfied. */
12994  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12995  assert( origcons != NULL );
12996  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12997 
12998  for (v = 0; v < nvars; ++v)
12999  {
13000  int image;
13001 
13002  assert ( SCIPhashmapExists(varhash, vars[v]) );
13003  image = SCIPhashmapGetImageInt(varhash, vars[v]);
13004  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
13005  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
13006  }
13007  }
13008  }
13009  }
13010  SCIPhashmapFree(&varhash);
13011  SCIPfreeBufferArray(scip, &cardweights);
13012  SCIPfreeBufferArray(scip, &cardvars);
13013 
13014  if ( *nupgdconss > noldupgdconss )
13015  success = TRUE;
13016  }
13017 #endif
13018 
13019  if( cutoff )
13020  *result = SCIP_CUTOFF;
13021  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
13022  *result = SCIP_SUCCESS;
13023  else
13024  *result = SCIP_DIDNOTFIND;
13025 
13026  return SCIP_OKAY;
13027 }
13028 
13029 /** propagation conflict resolving method of constraint handler */
13030 static
13031 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
13032 { /*lint --e{715}*/
13033  SCIP_CONSDATA* consdata;
13034  SCIP_Longint capsum;
13035  int i;
13036 
13037  assert(result != NULL);
13038 
13039  consdata = SCIPconsGetData(cons);
13040  assert(consdata != NULL);
13041 
13042  /* check if we fixed a binary variable to one (due to negated clique) */
13043  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
13044  {
13045  for( i = 0; i < consdata->nvars; ++i )
13046  {
13047  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
13048  {
13049  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13050  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13051  break;
13052  }
13053  }
13054  assert(i < consdata->nvars);
13055  }
13056  else
13057  {
13058  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13059  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13060  * knapsack constraint, see one above call of SCIPinferBinvarCons
13061  */
13062  if( inferinfo < 0 )
13063  capsum = 0;
13064  else
13065  {
13066  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13067  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13068  */
13069  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13070  capsum = consdata->weights[inferinfo];
13071  else
13072  {
13073  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13074  {}
13075  assert(i < consdata->nvars);
13076  capsum = consdata->weights[i];
13077  }
13078  }
13079 
13080  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13081  * the capacity
13082  */
13083  if( capsum <= consdata->capacity )
13084  {
13085  for( i = 0; i < consdata->nvars; i++ )
13086  {
13087  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13088  {
13089  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13090  capsum += consdata->weights[i];
13091  if( capsum > consdata->capacity )
13092  break;
13093  }
13094  }
13095  }
13096  }
13097 
13098  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13099  * to zero can included negated clique information. A negated clique means, that at most one of the clique
13100  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13101  * used to fix variables to zero.
13102  *
13103  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13104  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13105  * one.
13106  */
13107  *result = SCIP_SUCCESS;
13108 
13109  return SCIP_OKAY;
13110 }
13111 
13112 /** variable rounding lock method of constraint handler */
13113 /**! [SnippetConsLockKnapsack] */
13114 static
13115 SCIP_DECL_CONSLOCK(consLockKnapsack)
13116 { /*lint --e{715}*/
13117  SCIP_CONSDATA* consdata;
13118  int i;
13119 
13120  consdata = SCIPconsGetData(cons);
13121  assert(consdata != NULL);
13122 
13123  for( i = 0; i < consdata->nvars; i++)
13124  {
13125  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13126  }
13127 
13128  return SCIP_OKAY;
13129 }
13130 /**! [SnippetConsLockKnapsack] */
13131 
13132 /** constraint activation notification method of constraint handler */
13133 static
13134 SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13135 { /*lint --e{715}*/
13136  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisNLPConstructed(scip) )
13137  {
13138  SCIP_CALL( addNlrow(scip, cons) );
13139  }
13140 
13141  return SCIP_OKAY;
13143 
13144 /** constraint deactivation notification method of constraint handler */
13145 static
13146 SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13147 { /*lint --e{715}*/
13148  SCIP_CONSDATA* consdata;
13149 
13150  assert(cons != NULL);
13151 
13152  consdata = SCIPconsGetData(cons);
13153  assert(consdata != NULL);
13155  /* remove row from NLP, if still in solving
13156  * if we are in exitsolve, the whole NLP will be freed anyway
13157  */
13158  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13159  {
13160  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13161  }
13162 
13163  return SCIP_OKAY;
13164 }
13165 
13166 /** variable deletion method of constraint handler */
13167 static
13168 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13169 {
13170  assert(scip != NULL);
13171  assert(conshdlr != NULL);
13172  assert(conss != NULL || nconss == 0);
13173 
13174  if( nconss > 0 )
13175  {
13176  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13177  }
13178 
13179  return SCIP_OKAY;
13180 }
13181 
13182 /** constraint display method of constraint handler */
13183 static
13184 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13185 { /*lint --e{715}*/
13186  SCIP_CONSDATA* consdata;
13187  int i;
13188 
13189  assert( scip != NULL );
13190  assert( conshdlr != NULL );
13191  assert( cons != NULL );
13193  consdata = SCIPconsGetData(cons);
13194  assert(consdata != NULL);
13195 
13196  for( i = 0; i < consdata->nvars; ++i )
13197  {
13198  if( i > 0 )
13199  SCIPinfoMessage(scip, file, " ");
13200  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13201  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13202  }
13203  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13204 
13205  return SCIP_OKAY;
13206 }
13207 
13208 /** constraint copying method of constraint handler */
13209 static
13210 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13211 { /*lint --e{715}*/
13212  SCIP_VAR** sourcevars;
13213  SCIP_Longint* weights;
13214  SCIP_Real* coefs;
13215  const char* consname;
13216  int nvars;
13217  int v;
13219  /* get variables and coefficients of the source constraint */
13220  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13221  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13222  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13223 
13224  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13225  for( v = 0; v < nvars; ++v )
13226  coefs[v] = (SCIP_Real) weights[v];
13227 
13228  if( name != NULL )
13229  consname = name;
13230  else
13231  consname = SCIPconsGetName(sourcecons);
13232 
13233  /* copy the logic using the linear constraint copy method */
13234  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13235  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13236  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13237  assert(cons != NULL);
13238 
13239  SCIPfreeBufferArray(scip, &coefs);
13240 
13241  return SCIP_OKAY;
13242 }
13243 
13244 /** constraint parsing method of constraint handler */
13245 static
13246 SCIP_DECL_CONSPARSE(consParseKnapsack)
13247 { /*lint --e{715}*/
13248  SCIP_VAR* var;
13249  SCIP_Longint weight;
13250  SCIP_VAR** vars;
13251  SCIP_Longint* weights;
13252  SCIP_Longint capacity;
13253  char* endptr;
13254  int nread;
13255  int nvars;
13256  int varssize;
13257 
13258  assert(scip != NULL);
13259  assert(success != NULL);
13260  assert(str != NULL);
13261  assert(name != NULL);
13262  assert(cons != NULL);
13263 
13264  *success = TRUE;
13265 
13266  nvars = 0;
13267  varssize = 5;
13268  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13269  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13270 
13271  while( *str != '\0' )
13272  {
13273  /* try to parse coefficient, and use 1 if not successful */
13274  weight = 1;
13275  nread = 0;
13276  (void) sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13277  str += nread;
13278 
13279  /* parse variable name */
13280  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13281 
13282  if( var == NULL )
13283  {
13284  endptr = strchr(endptr, '<');
13285 
13286  if( endptr == NULL )
13287  {
13288  SCIPerrorMessage("no capacity found\n");
13289  *success = FALSE;
13290  }
13291  else
13292  str = endptr;
13293 
13294  break;
13295  }
13296 
13297  str = endptr;
13298 
13299  /* store weight and variable */
13300  if( varssize <= nvars )
13301  {
13302  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13303  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13304  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13305  }
13306 
13307  vars[nvars] = var;
13308  weights[nvars] = weight;
13309  ++nvars;
13310 
13311  /* skip whitespace */
13312  SCIP_CALL( SCIPskipSpace((char**)&str) );
13313  }
13314 
13315  if( *success )
13316  {
13317  if( strncmp(str, "<=", 2) != 0 )
13318  {
13319  SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13320  *success = FALSE;
13321  }
13322  else
13323  {
13324  str += 2;
13325  }
13326  }
13327 
13328  if( *success )
13329  {
13330  /* skip whitespace */
13331  SCIP_CALL( SCIPskipSpace((char**)&str) );
13332 
13333  /* coverity[secure_coding] */
13334  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13335  {
13336  SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13337  *success = FALSE;
13338  }
13339  else
13340  {
13341  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13342  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13343  }
13344  }
13345 
13346  SCIPfreeBufferArray(scip, &vars);
13347  SCIPfreeBufferArray(scip, &weights);
13348 
13349  return SCIP_OKAY;
13350 }
13351 
13352 /** constraint method of constraint handler which returns the variables (if possible) */
13353 static
13354 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13355 { /*lint --e{715}*/
13356  SCIP_CONSDATA* consdata;
13357 
13358  consdata = SCIPconsGetData(cons);
13359  assert(consdata != NULL);
13360 
13361  if( varssize < consdata->nvars )
13362  (*success) = FALSE;
13363  else
13364  {
13365  assert(vars != NULL);
13366 
13367  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13368  (*success) = TRUE;
13369  }
13370 
13371  return SCIP_OKAY;
13372 }
13373 
13374 /** constraint method of constraint handler which returns the number of variables (if possible) */
13375 static
13376 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13377 { /*lint --e{715}*/
13378  SCIP_CONSDATA* consdata;
13379 
13380  consdata = SCIPconsGetData(cons);
13381  assert(consdata != NULL);
13382 
13383  (*nvars) = consdata->nvars;
13384  (*success) = TRUE;
13385 
13386  return SCIP_OKAY;
13387 }
13388 
13389 /** constraint handler method which returns the permutation symmetry detection graph of a constraint */
13390 static
13391 SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
13392 { /*lint --e{715}*/
13393  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
13394 
13395  return SCIP_OKAY;
13396 }
13397 
13398 /** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
13399 static
13400 SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
13401 { /*lint --e{715}*/
13402  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
13403 
13404  return SCIP_OKAY;
13405 }
13406 
13407 /*
13408  * Event handler
13409  */
13410 
13411 /** execution method of bound change event handler */
13412 static
13413 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13414 { /*lint --e{715}*/
13415  SCIP_CONSDATA* consdata;
13416 
13417  assert(eventdata != NULL);
13418  assert(eventdata->cons != NULL);
13419 
13420  consdata = SCIPconsGetData(eventdata->cons);
13421  assert(consdata != NULL);
13422 
13423  switch( SCIPeventGetType(event) )
13424  {
13426  consdata->onesweightsum += eventdata->weight;
13427  consdata->presolvedtiming = 0;
13428  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13429  break;
13431  consdata->onesweightsum -= eventdata->weight;
13432  break;
13434  consdata->presolvedtiming = 0;
13435  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13436  break;
13437  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13438  if( !consdata->existmultaggr )
13439  {
13440  SCIP_VAR* var;
13441  var = SCIPeventGetVar(event);
13442  assert(var != NULL);
13443 
13444  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13446  {
13447  consdata->existmultaggr = TRUE;
13448  consdata->merged = FALSE;
13449  }
13450  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13452  consdata->merged = FALSE;
13453  }
13454  /*lint -fallthrough*/
13455  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13456  consdata->presolvedtiming = 0;
13457  break;
13459  consdata->varsdeleted = TRUE;
13460  break;
13461  default:
13462  SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13463  return SCIP_INVALIDDATA;
13464  }
13465 
13466  return SCIP_OKAY;
13467 }
13468 
13469 
13470 /*
13471  * constraint specific interface methods
13472  */
13473 
13474 /** creates the handler for knapsack constraints and includes it in SCIP */
13476  SCIP* scip /**< SCIP data structure */
13477  )
13478 {
13479  SCIP_EVENTHDLRDATA* eventhdlrdata;
13480  SCIP_CONSHDLRDATA* conshdlrdata;
13481  SCIP_CONSHDLR* conshdlr;
13482 
13483  /* create knapsack constraint handler data */
13484  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13485 
13486  /* include event handler for bound change events */
13487  eventhdlrdata = NULL;
13488  conshdlrdata->eventhdlr = NULL;
13489  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13490  eventExecKnapsack, eventhdlrdata) );
13491 
13492  /* get event handler for bound change events */
13493  if( conshdlrdata->eventhdlr == NULL )
13494  {
13495  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13496  return SCIP_PLUGINNOTFOUND;
13497  }
13498 
13499  /* include constraint handler */
13502  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13503  conshdlrdata) );
13504 
13505  assert(conshdlr != NULL);
13506 
13507  /* set non-fundamental callbacks via specific setter functions */
13508  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13509  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13510  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13511  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13512  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13513  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13514  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13515  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13516  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13517  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13518  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13519  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13520  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13521  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13522  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13523  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13524  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13525  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13526  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13528  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13529  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13531  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13532  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13533  SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
13534  SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
13535 
13536  if( SCIPfindConshdlr(scip,"linear") != NULL )
13537  {
13538  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13540  }
13541 
13542  /* add knapsack constraint handler parameters */
13543  SCIP_CALL( SCIPaddIntParam(scip,
13544  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13545  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13546  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13548  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13549  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13550  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13552  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13553  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13554  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13555  SCIP_CALL( SCIPaddIntParam(scip,
13556  "constraints/" CONSHDLR_NAME "/maxrounds",
13557  "maximal number of separation rounds per node (-1: unlimited)",
13558  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13559  SCIP_CALL( SCIPaddIntParam(scip,
13560  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13561  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13562  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13563  SCIP_CALL( SCIPaddIntParam(scip,
13564  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13565  "maximal number of cuts separated per separation round",
13566  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13567  SCIP_CALL( SCIPaddIntParam(scip,
13568  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13569  "maximal number of cuts separated per separation round in the root node",
13570  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13572  "constraints/" CONSHDLR_NAME "/disaggregation",
13573  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13574  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13576  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13577  "should presolving try to simplify knapsacks",
13578  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13580  "constraints/" CONSHDLR_NAME "/negatedclique",
13581  "should negated clique information be used in solving process",
13582  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13584  "constraints/" CONSHDLR_NAME "/presolpairwise",
13585  "should pairwise constraint comparison be performed in presolving?",
13586  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13588  "constraints/" CONSHDLR_NAME "/presolusehashing",
13589  "should hash table be used for detecting redundant constraints in advance",
13590  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13592  "constraints/" CONSHDLR_NAME "/dualpresolving",
13593  "should dual presolving steps be performed?",
13594  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13596  "constraints/" CONSHDLR_NAME "/usegubs",
13597  "should GUB information be used for separation?",
13598  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13600  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13601  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13602  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13604  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13605  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13606  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13608  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13609  "should clique partition information be updated when old partition seems outdated?",
13610  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13612  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13613  "factor on the growth of global cliques to decide when to update a previous "
13614  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13615  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13616 #ifdef WITH_CARDINALITY_UPGRADE
13618  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13619  "if TRUE then try to update knapsack constraints to cardinality constraints",
13620  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13621 #endif
13622  return SCIP_OKAY;
13623 }
13624 
13625 /** creates and captures a knapsack constraint
13626  *
13627  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13628  */
13629 /**! [SnippetConsCreationKnapsack] */
13631  SCIP* scip, /**< SCIP data structure */
13632  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13633  const char* name, /**< name of constraint */
13634  int nvars, /**< number of items in the knapsack */
13635  SCIP_VAR** vars, /**< array with item variables */
13636  SCIP_Longint* weights, /**< array with item weights */
13637  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13638  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13639  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13640  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13641  * Usually set to TRUE. */
13642  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13643  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13644  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13645  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13646  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13647  * Usually set to TRUE. */
13648  SCIP_Bool local, /**< is constraint only valid locally?
13649  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13650  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13651  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13652  * adds coefficients to this constraint. */
13653  SCIP_Bool dynamic, /**< is constraint subject to aging?
13654  * Usually set to FALSE. Set to TRUE for own cuts which
13655  * are separated as constraints. */
13656  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13657  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13658  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13659  * if it may be moved to a more global node?
13660  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13661  )
13662 {
13663  SCIP_CONSHDLRDATA* conshdlrdata;
13664  SCIP_CONSHDLR* conshdlr;
13665  SCIP_CONSDATA* consdata;
13666 
13667  /* find the knapsack constraint handler */
13668  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13669  if( conshdlr == NULL )
13670  {
13671  SCIPerrorMessage("knapsack constraint handler not found\n");
13672  return SCIP_PLUGINNOTFOUND;
13673  }
13674 
13675  /* get event handler */
13676  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13677  assert(conshdlrdata != NULL);
13678  assert(conshdlrdata->eventhdlr != NULL);
13679 
13680  /* create constraint data */
13681  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13682 
13683  /* create constraint */
13684  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13685  local, modifiable, dynamic, removable, stickingatnode) );
13686 
13687  /* catch events for variables */
13688  if( SCIPisTransformed(scip) )
13689  {
13690  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13691  }
13692 
13693  return SCIP_OKAY;
13694 }
13695 /**! [SnippetConsCreationKnapsack] */
13696 
13697 /** creates and captures a knapsack constraint
13698  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13699  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13700  *
13701  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13702  *
13703  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13704  */
13706  SCIP* scip, /**< SCIP data structure */
13707  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13708  const char* name, /**< name of constraint */
13709  int nvars, /**< number of items in the knapsack */
13710  SCIP_VAR** vars, /**< array with item variables */
13711  SCIP_Longint* weights, /**< array with item weights */
13712  SCIP_Longint capacity /**< capacity of knapsack */
13713  )
13714 {
13715  assert(scip != NULL);
13716 
13717  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13718  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13719 
13720  return SCIP_OKAY;
13721 }
13722 
13723 /** adds new item to knapsack constraint */
13725  SCIP* scip, /**< SCIP data structure */
13726  SCIP_CONS* cons, /**< constraint data */
13727  SCIP_VAR* var, /**< item variable */
13728  SCIP_Longint weight /**< item weight */
13729  )
13730 {
13731  assert(var != NULL);
13732  assert(scip != NULL);
13733 
13734  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13735  {
13736  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13737  return SCIP_INVALIDDATA;
13738  }
13739 
13740  SCIP_CALL( addCoef(scip, cons, var, weight) );
13741 
13742  return SCIP_OKAY;
13743 }
13744 
13745 /** gets the capacity of the knapsack constraint */
13747  SCIP* scip, /**< SCIP data structure */
13748  SCIP_CONS* cons /**< constraint data */
13749  )
13750 {
13751  SCIP_CONSDATA* consdata;
13752 
13753  assert(scip != NULL);
13755  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13756  {
13757  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13758  SCIPABORT();
13759  return 0; /*lint !e527*/
13760  }
13761 
13762  consdata = SCIPconsGetData(cons);
13763  assert(consdata != NULL);
13764 
13765  return consdata->capacity;
13766 }
13767 
13768 /** changes capacity of the knapsack constraint
13769  *
13770  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13771  */
13773  SCIP* scip, /**< SCIP data structure */
13774  SCIP_CONS* cons, /**< constraint data */
13775  SCIP_Longint capacity /**< new capacity of knapsack */
13776  )
13777 {
13778  SCIP_CONSDATA* consdata;
13779 
13780  assert(scip != NULL);
13781 
13782  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13783  {
13784  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13785  return SCIP_INVALIDDATA;
13786  }
13787 
13788  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13789  {
13790  SCIPerrorMessage("method can only be called during problem creation stage\n");
13791  return SCIP_INVALIDDATA;
13792  }
13793 
13794  consdata = SCIPconsGetData(cons);
13795  assert(consdata != NULL);
13796 
13797  consdata->capacity = capacity;
13798 
13799  return SCIP_OKAY;
13800 }
13801 
13802 /** gets the number of items in the knapsack constraint */
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 -1; /*lint !e527*/
13817  }
13818 
13819  consdata = SCIPconsGetData(cons);
13820  assert(consdata != NULL);
13821 
13822  return consdata->nvars;
13823 }
13824 
13825 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13827  SCIP* scip, /**< SCIP data structure */
13828  SCIP_CONS* cons /**< constraint data */
13829  )
13830 {
13831  SCIP_CONSDATA* consdata;
13832 
13833  assert(scip != NULL);
13835  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13836  {
13837  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13838  SCIPABORT();
13839  return NULL; /*lint !e527*/
13840  }
13841 
13842  consdata = SCIPconsGetData(cons);
13843  assert(consdata != NULL);
13844 
13845  return consdata->vars;
13846 }
13847 
13848 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13850  SCIP* scip, /**< SCIP data structure */
13851  SCIP_CONS* cons /**< constraint data */
13852  )
13853 {
13854  SCIP_CONSDATA* consdata;
13855 
13856  assert(scip != NULL);
13858  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13859  {
13860  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13861  SCIPABORT();
13862  return NULL; /*lint !e527*/
13863  }
13864 
13865  consdata = SCIPconsGetData(cons);
13866  assert(consdata != NULL);
13867 
13868  return consdata->weights;
13869 }
13870 
13871 /** gets the dual solution of the knapsack constraint in the current LP */
13873  SCIP* scip, /**< SCIP data structure */
13874  SCIP_CONS* cons /**< constraint data */
13875  )
13876 {
13877  SCIP_CONSDATA* consdata;
13878 
13879  assert(scip != NULL);
13881  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13882  {
13883  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13884  SCIPABORT();
13885  return SCIP_INVALID; /*lint !e527*/
13886  }
13887 
13888  consdata = SCIPconsGetData(cons);
13889  assert(consdata != NULL);
13890 
13891  if( consdata->row != NULL )
13892  return SCIProwGetDualsol(consdata->row);
13893  else
13894  return 0.0;
13895 }
13896 
13897 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13899  SCIP* scip, /**< SCIP data structure */
13900  SCIP_CONS* cons /**< constraint data */
13901  )
13902 {
13903  SCIP_CONSDATA* consdata;
13904 
13905  assert(scip != NULL);
13907  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13908  {
13909  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13910  SCIPABORT();
13911  return SCIP_INVALID; /*lint !e527*/
13912  }
13913 
13914  consdata = SCIPconsGetData(cons);
13915  assert(consdata != NULL);
13916 
13917  if( consdata->row != NULL )
13918  return SCIProwGetDualfarkas(consdata->row);
13919  else
13920  return 0.0;
13921 }
13922 
13923 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13924  * the user must not modify the row!
13925  */
13927  SCIP* scip, /**< SCIP data structure */
13928  SCIP_CONS* cons /**< constraint data */
13929  )
13930 {
13931  SCIP_CONSDATA* consdata;
13932 
13933  assert(scip != NULL);
13935  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13936  {
13937  SCIPerrorMessage("constraint is not a knapsack\n");
13938  SCIPABORT();
13939  return NULL; /*lint !e527*/
13940  }
13941 
13942  consdata = SCIPconsGetData(cons);
13943  assert(consdata != NULL);
13944 
13945  return consdata->row;
13946 }
13947 
13948 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
13950  SCIP* scip, /**< SCIP data structure */
13951  SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13952  SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13953  )
13954 {
13955  SCIP_CONSHDLR* conshdlr;
13956  SCIP_CONS** conss;
13957  int nconss;
13958  int i;
13959 
13960  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13961  if( conshdlr == NULL )
13962  return SCIP_OKAY;
13963 
13964  assert(infeasible != NULL);
13965  *infeasible = FALSE;
13966 
13967  nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13968  conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13969 
13970  for( i = 0; i < nconss; ++i )
13971  {
13972  SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13973 
13974  if( *infeasible )
13975  break;
13976  }
13977 
13978  return SCIP_OKAY;
13979 }
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:4229
#define DEFAULT_DETECTCUTOFFBOUND
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1785
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:1692
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
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:18293
#define NULL
Definition: def.h:267
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:11476
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:10866
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:5202
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:2127
#define CONSHDLR_DESC
Definition: cons_knapsack.c:82
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
static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
#define CONSHDLR_PROP_TIMING
Definition: cons_knapsack.c:97
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:72
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8475
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17871
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:1596
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:3357
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:1991
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2547
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:941
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:18271
#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:18079
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
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:12311
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
#define SCIP_MAXSTRLEN
Definition: def.h:288
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:84
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:323
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1813
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:17859
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:1372
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:1559
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18135
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:18442
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:693
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:1525
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:1247
static SCIP_DECL_CONSCHECK(consCheckKnapsack)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17600
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:492
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:86
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:4595
#define FALSE
Definition: def.h:94
#define MAX_CLIQUELENGTH
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3074
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11184
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:181
#define CONSHDLR_MAXPREROUNDS
Definition: cons_knapsack.c:91
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:93
#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:2043
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:88
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8495
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18313
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:3192
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17769
SCIP_Longint SCIPsepaGetNCutsFound(SCIP_SEPA *sepa)
Definition: sepa.c:900
SCIP_Longint SCIPconshdlrGetNCutsFound(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4902
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:8525
public methods for problem variables
#define SCIPhashSix(a, b, c, d, e, f)
Definition: pub_misc.h:563
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:5319
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define EVENTHDLR_NAME
Definition: cons_knapsack.c:99
#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:235
SCIP_Real SCIPgetDualsolKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18283
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:5132
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:159
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:596
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:762
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8485
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
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:1479
#define CONSHDLR_PRESOLTIMING
Definition: cons_knapsack.c:96
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:808
#define DEFAULT_PRESOLUSEHASHING
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8277
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:18431
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:998
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:2296
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:17895
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17523
#define DEFAULT_SEPACARDFREQ
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3423
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4258
#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:1297
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:6920
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:18089
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:12219
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:444
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:83
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 .
methods for dealing with symmetry detection graphs
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:633
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition: nlp.c:1956
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:347
static SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
static SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
enum GUBVarstatus GUBVARSTATUS
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
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:4199
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:396
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:1254
static void GUBsetSwapVars(SCIP *scip, SCIP_GUBSET *gubset, int var1, int var2)
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
Definition: scip_cons.c:900
#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:1058
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)
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
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:4436
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip_cons.c:1347
static SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8216
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18345
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8435
#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:17420
static SCIP_DECL_CONSACTIVE(consActiveKnapsack)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3108
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4219
static SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
static SCIP_Longint safeAddMinweightsGUB(SCIP_Longint val1, SCIP_Longint val2)
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2015
structs for symmetry computations
static SCIP_DECL_CONSPRINT(consPrintKnapsack)
#define REALABS(x)
Definition: def.h:197
#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:380
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:18303
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17883
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:2677
GUBVARSTATUS * gubvarsstatus
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:141
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:18335
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8455
#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 SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
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:9417
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:18389
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:91
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:92
#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:18357
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:2537
static SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
static SCIP_RETCODE eventdataCreate(SCIP *scip, SCIP_EVENTDATA **eventdata, SCIP_CONS *cons, SCIP_Longint weight)
SCIP_RETCODE SCIPcalcCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7255
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8236
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11943
#define MIN(x, y)
Definition: def.h:243
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:8345
#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:8415
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8385
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17927
#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
#define CONSHDLR_NAME
Definition: cons_knapsack.c:81
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:954
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8275
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
static void sortItems(SCIP_CONSDATA *consdata)
#define CONSHDLR_DELAYPROP
Definition: cons_knapsack.c:93
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:4350
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:64
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:785
#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:2608
int * gubvarsidx
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17847
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:18403
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:316
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4672
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
Definition: scip_cons.c:924
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:2346
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:424
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:18374
#define SCIP_LONGINT_FORMAT
Definition: def.h:165
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
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
#define MAX(x, y)
Definition: def.h:239
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:8246
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:396
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4615
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:1322
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:420
#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:1174
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:540
public methods for message output
#define HASHSIZE_KNAPSACKCONS
enum GUBConsstatus GUBCONSSTATUS
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:7574
#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:17539
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPcalcNegatedCliquePartition(SCIP *const scip, SCIP_VAR **const vars, int const nvars, int *const cliquepartition, int *const ncliques)
Definition: scip_var.c:7474
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1213
static SCIP_RETCODE GUBconsAddVar(SCIP *scip, SCIP_GUBCONS *gubcons, int var)
#define SCIP_Real
Definition: def.h:173
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8465
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:724
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:12279
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
#define GUBCONSGROWVALUE
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4658
public methods for message handling
static SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8405
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
#define SCIP_INVALID
Definition: def.h:193
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8395
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18325
static SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
static SCIP_RETCODE removeZeroWeights(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_MAXROUNDSROOT
#define CONSHDLR_PROPFREQ
Definition: cons_knapsack.c:87
#define CONSHDLR_NEEDSCONS
Definition: cons_knapsack.c:94
SCIP_Real SCIPcutoffbounddelta(SCIP *scip)
#define SCIP_Longint
Definition: def.h:158
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:9557
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17759
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:18145
#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:17562
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:130
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:670
#define USESUPADDLIFT
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
#define NMINCOMPARISONS
static SCIP_DECL_CONSTRANS(consTransKnapsack)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3281
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:468
SCIP_ROW * SCIPgetRowKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPABORT()
Definition: def.h:352
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:17611
#define MAXCOVERSIZEITERLEWI
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9121
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
SCIP_Bool SCIPvarIsDeleted(SCIP_VAR *var)
Definition: var.c:17641
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:8628
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:5722
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:85
#define SCIP_EVENTTYPE_VARDELETED
Definition: type_event.h:71
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1526
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:17749
static void computeMinweightsGUB(SCIP_Longint *minweights, SCIP_Longint *finished, SCIP_Longint *unfinished, int minweightslen)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17575
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:281
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1272
void SCIPsortDownLongPtrInt(SCIP_Longint *longarray, void **ptrarray, int *intarray, int len)
memory allocation routines