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 sum;
1000  SCIP_Longint integralsum;
1001  SCIP_Bool ishuge;
1002  SCIP_Real absviol;
1003  SCIP_Real relviol;
1004  int v;
1005 
1006  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1007  * enforcement
1008  */
1009  if( sol == NULL )
1010  {
1011  SCIP_CALL( SCIPincConsAge(scip, cons) );
1012  }
1013 
1014  sum = 0.0;
1015  integralsum = 0;
1016  /* we perform a more exact comparison if the capacity does not exceed the huge value */
1017  if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
1018  {
1019  ishuge = TRUE;
1020 
1021  /* sum over all weight times the corresponding solution value */
1022  for( v = consdata->nvars - 1; v >= 0; --v )
1023  {
1024  assert(SCIPvarIsBinary(consdata->vars[v]));
1025  sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
1026  }
1027  }
1028  else
1029  {
1030  ishuge = FALSE;
1031 
1032  /* sum over all weight for which the variable has a solution value of 1 in feastol */
1033  for( v = consdata->nvars - 1; v >= 0; --v )
1034  {
1035  assert(SCIPvarIsBinary(consdata->vars[v]));
1036 
1037  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
1038  integralsum += consdata->weights[v];
1039  }
1040  }
1041 
1042  /* calculate constraint violation and update it in solution */
1043  absviol = ishuge ? sum : (SCIP_Real)integralsum;
1044  absviol -= consdata->capacity;
1045  relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
1046  if( sol != NULL )
1047  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1048 
1049  if( SCIPisFeasPositive(scip, absviol) )
1050  {
1051  *violated = TRUE;
1052 
1053  /* only reset constraint age if we are in enforcement */
1054  if( sol == NULL )
1055  {
1056  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1057  }
1058 
1059  if( printreason )
1060  {
1061  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1062 
1063  SCIPinfoMessage(scip, NULL, ";\n");
1064  SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1065  }
1066  }
1067  }
1068 
1069  return SCIP_OKAY;
1070 }
1071 
1072 /* IDX computes the integer index for the optimal solution array */
1073 #define IDX(j,d) ((j)*(intcap)+(d))
1074 
1075 /** solves knapsack problem in maximization form exactly using dynamic programming;
1076  * if needed, one can provide arrays to store all selected items and all not selected items
1077  *
1078  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1079  *
1080  * @note the algorithm will first compute a greedy solution and terminate
1081  * if the greedy solution is proven to be optimal.
1082  * The dynamic programming algorithm runs with a time and space complexity
1083  * of O(nitems * capacity).
1084  *
1085  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1086  * There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1087  * to be checked whether they are faster and whether they can reconstruct the solution.
1088  * Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1089  * This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1090  * This could be implemented, however, it would be technically a bit cumbersome,
1091  * since one needs the greedy solution and the LP-value for this.
1092  * This is currently only available after the redundant items have already been sorted out.
1093  */
1095  SCIP* scip, /**< SCIP data structure */
1096  int nitems, /**< number of available items */
1097  SCIP_Longint* weights, /**< item weights */
1098  SCIP_Real* profits, /**< item profits */
1099  SCIP_Longint capacity, /**< capacity of knapsack */
1100  int* items, /**< item numbers */
1101  int* solitems, /**< array to store items in solution, or NULL */
1102  int* nonsolitems, /**< array to store items not in solution, or NULL */
1103  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1104  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1105  SCIP_Real* solval, /**< pointer to store optimal solution value, or NULL */
1106  SCIP_Bool* success /**< pointer to store if an error occured during solving
1107  * (normally a memory problem) */
1108  )
1109 {
1110  SCIP_RETCODE retcode;
1111  SCIP_Real* tempsort;
1112  SCIP_Real* optvalues;
1113  int intcap;
1114  int d;
1115  int j;
1116  int greedymedianpos;
1117  SCIP_Longint weightsum;
1118  int* myitems;
1119  SCIP_Longint* myweights;
1120  SCIP_Real* realweights;
1121  int* allcurrminweight;
1122  SCIP_Real* myprofits;
1123  int nmyitems;
1124  SCIP_Longint gcd;
1125  SCIP_Longint minweight;
1126  SCIP_Longint maxweight;
1127  int currminweight;
1128  SCIP_Longint greedysolweight;
1129  SCIP_Real greedysolvalue;
1130  SCIP_Real greedyupperbound;
1131  SCIP_Bool eqweights;
1132  SCIP_Bool intprofits;
1133 
1134  assert(weights != NULL);
1135  assert(profits != NULL);
1136  assert(capacity >= 0);
1137  assert(items != NULL);
1138  assert(nitems >= 0);
1139  assert(success != NULL);
1140 
1141  *success = TRUE;
1142 
1143 #ifndef NDEBUG
1144  for( j = nitems - 1; j >= 0; --j )
1145  assert(weights[j] >= 0);
1146 #endif
1147 
1148  SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1149 
1150  /* initializing solution value */
1151  if( solval != NULL )
1152  *solval = 0.0;
1153 
1154  /* init solution information */
1155  if( solitems != NULL )
1156  {
1157  assert(items != NULL);
1158  assert(nsolitems != NULL);
1159  assert(nonsolitems != NULL);
1160  assert(nnonsolitems != NULL);
1161 
1162  *nnonsolitems = 0;
1163  *nsolitems = 0;
1164  }
1165 
1166  /* allocate temporary memory */
1167  SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1168  SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1169  SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1170  nmyitems = 0;
1171  weightsum = 0;
1172  minweight = SCIP_LONGINT_MAX;
1173  maxweight = 0;
1174 
1175  /* remove unnecessary items */
1176  for( j = 0; j < nitems; ++j )
1177  {
1178  assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1179 
1180  /* item does not fit */
1181  if( weights[j] > capacity )
1182  {
1183  if( solitems != NULL )
1184  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1185  }
1186  /* item is not profitable */
1187  else if( profits[j] <= 0.0 )
1188  {
1189  if( solitems != NULL )
1190  nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1191  }
1192  /* item always fits */
1193  else if( weights[j] == 0 )
1194  {
1195  if( solitems != NULL )
1196  solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1197 
1198  if( solval != NULL )
1199  *solval += profits[j];
1200  }
1201  /* all important items */
1202  else
1203  {
1204  myweights[nmyitems] = weights[j];
1205  myprofits[nmyitems] = profits[j];
1206  myitems[nmyitems] = items[j];
1207 
1208  /* remember smallest item */
1209  if( myweights[nmyitems] < minweight )
1210  minweight = myweights[nmyitems];
1211 
1212  /* remember bigest item */
1213  if( myweights[nmyitems] > maxweight )
1214  maxweight = myweights[nmyitems];
1215 
1216  weightsum += myweights[nmyitems];
1217  ++nmyitems;
1218  }
1219  }
1220 
1221  intprofits = TRUE;
1222  /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1223  for( j = 0; j < nmyitems && intprofits; ++j )
1224  intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1225 
1226  /* if no item is left then goto end */
1227  if( nmyitems == 0 )
1228  {
1229  SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1230 
1231  goto TERMINATE;
1232  }
1233 
1234  /* if all items fit, we also do not need to do the expensive stuff later on */
1235  if( weightsum > 0 && weightsum <= capacity )
1236  {
1237  SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1238 
1239  for( j = nmyitems - 1; j >= 0; --j )
1240  {
1241  if( solitems != NULL )
1242  solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1243 
1244  if( solval != NULL )
1245  *solval += myprofits[j];
1246  }
1247 
1248  goto TERMINATE;
1249  }
1250 
1251  assert(0 < minweight && minweight <= capacity );
1252  assert(0 < maxweight && maxweight <= capacity);
1253 
1254  /* make weights relatively prime */
1255  eqweights = TRUE;
1256  if( maxweight > 1 )
1257  {
1258  /* determine greatest common divisor */
1259  gcd = myweights[nmyitems - 1];
1260  for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1261  gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1262 
1263  SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1264 
1265  /* divide by greatest common divisor */
1266  if( gcd > 1 )
1267  {
1268  for( j = nmyitems - 1; j >= 0; --j )
1269  {
1270  myweights[j] /= gcd;
1271  eqweights = eqweights && (myweights[j] == 1);
1272  }
1273  capacity /= gcd;
1274  minweight /= gcd;
1275  }
1276  else
1277  eqweights = FALSE;
1278  }
1279  assert(minweight <= capacity);
1280 
1281  /* if only one item fits, then take the best */
1282  if( minweight > capacity / 2 )
1283  {
1284  int p;
1285 
1286  SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1287 
1288  p = nmyitems - 1;
1289 
1290  /* find best item */
1291  for( j = nmyitems - 2; j >= 0; --j )
1292  {
1293  if( myprofits[j] > myprofits[p] )
1294  p = j;
1295  }
1296 
1297  /* update solution information */
1298  if( solitems != NULL )
1299  {
1300  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1301 
1302  solitems[(*nsolitems)++] = myitems[p];
1303  for( j = nmyitems - 1; j >= 0; --j )
1304  {
1305  if( j != p )
1306  nonsolitems[(*nnonsolitems)++] = myitems[j];
1307  }
1308  }
1309  /* update solution value */
1310  if( solval != NULL )
1311  *solval += myprofits[p];
1312 
1313  goto TERMINATE;
1314  }
1315 
1316  /* if all items have the same weight, then take the best */
1317  if( eqweights )
1318  {
1319  SCIP_Real addval = 0.0;
1320 
1321  SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1322 
1323  SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1324 
1325  /* update solution information */
1326  if( solitems != NULL || solval != NULL )
1327  {
1328  SCIP_Longint i;
1329 
1330  /* if all items would fit we had handled this case before */
1331  assert((SCIP_Longint) nmyitems > capacity);
1332  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1333 
1334  /* take the first best items into the solution */
1335  for( i = capacity - 1; i >= 0; --i )
1336  {
1337  if( solitems != NULL )
1338  solitems[(*nsolitems)++] = myitems[i];
1339  addval += myprofits[i];
1340  }
1341 
1342  if( solitems != NULL )
1343  {
1344  /* the rest are not in the solution */
1345  for( i = nmyitems - 1; i >= capacity; --i )
1346  nonsolitems[(*nnonsolitems)++] = myitems[i];
1347  }
1348  }
1349  /* update solution value */
1350  if( solval != NULL )
1351  {
1352  assert(addval > 0.0);
1353  *solval += addval;
1354  }
1355 
1356  goto TERMINATE;
1357  }
1358 
1359  SCIPdebugMsg(scip, "Determine greedy solution.\n");
1360 
1361  /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1362  * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1363  */
1364  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1365  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1366 
1367  for( j = 0; j < nmyitems; ++j )
1368  {
1369  tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1370  realweights[j] = (SCIP_Real)myweights[j];
1371  }
1372 
1373  SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1374  (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1375 
1376  SCIPfreeBufferArray(scip, &realweights);
1377  SCIPfreeBufferArray(scip, &tempsort);
1378 
1379  /* initialize values for greedy solution information */
1380  greedysolweight = 0;
1381  greedysolvalue = 0.0;
1382 
1383  /* determine greedy solution */
1384  for( j = 0; j < greedymedianpos; ++j )
1385  {
1386  assert(myweights[j] <= capacity);
1387 
1388  /* update greedy solution weight and value */
1389  greedysolweight += myweights[j];
1390  greedysolvalue += myprofits[j];
1391  }
1392 
1393  assert(0 < greedysolweight && greedysolweight <= capacity);
1394  assert(greedysolvalue > 0.0);
1395 
1396  /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1397  * - the greedy solution reaches the capacity, because then the LP solution is integral;
1398  * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1399  greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1400  if( intprofits )
1401  greedyupperbound = SCIPfloor(scip, greedyupperbound);
1402  if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1403  {
1404  SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1405 
1406  /* update solution information */
1407  if( solitems != NULL )
1408  {
1409  int l;
1410 
1411  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1412 
1413  /* collect items */
1414  for( l = 0; l < j; ++l )
1415  solitems[(*nsolitems)++] = myitems[l];
1416  for ( ; l < nmyitems; ++l )
1417  nonsolitems[(*nnonsolitems)++] = myitems[l];
1418  }
1419  /* update solution value */
1420  if( solval != NULL )
1421  {
1422  assert(greedysolvalue > 0.0);
1423  *solval += greedysolvalue;
1424  }
1425 
1426  goto TERMINATE;
1427  }
1428 
1429  /* in the following table we do not need the first minweight columns */
1430  capacity -= (minweight - 1);
1431 
1432  /* we can only handle integers */
1433  if( capacity >= INT_MAX )
1434  {
1435  SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1436 
1437  *success = FALSE;
1438  goto TERMINATE;
1439  }
1440  assert(capacity < INT_MAX);
1441 
1442  intcap = (int)capacity;
1443  assert(intcap >= 0);
1444  assert(nmyitems > 0);
1445  assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1446 
1447  /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1448  * computing the size for the allocation
1449  */
1450  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*/
1451  {
1452  SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1453 
1454  *success = FALSE;
1455  goto TERMINATE;
1456  }
1457 
1458  /* allocate temporary memory and check for memory exceedance */
1459  retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1460  if( retcode == SCIP_NOMEMORY )
1461  {
1462  SCIPdebugMsg(scip, "Did not get enough memory.\n");
1463 
1464  *success = FALSE;
1465  goto TERMINATE;
1466  }
1467  else
1468  {
1469  SCIP_CALL( retcode );
1470  }
1471 
1472  SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1473 
1474  /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1475  * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1476  * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1477  * 'nmyitem' values
1478  */
1479  SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1480  assert(myweights[0] - minweight < INT_MAX);
1481  currminweight = (int) (myweights[0] - minweight);
1482  allcurrminweight[0] = currminweight;
1483 
1484  /* fills first row of dynamic programming table with optimal values */
1485  for( d = currminweight; d < intcap; ++d )
1486  optvalues[d] = myprofits[0];
1487 
1488  /* fills dynamic programming table with optimal values */
1489  for( j = 1; j < nmyitems; ++j )
1490  {
1491  int intweight;
1492 
1493  /* compute important part of weight, which will be represented in the table */
1494  intweight = (int)(myweights[j] - minweight);
1495  assert(0 <= intweight && intweight < intcap);
1496 
1497  /* copy all nonzeros from row above */
1498  for( d = currminweight; d < intweight && d < intcap; ++d )
1499  optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1500 
1501  /* update corresponding row */
1502  for( d = intweight; d < intcap; ++d )
1503  {
1504  /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1505  if( d < currminweight )
1506  optvalues[IDX(j,d)] = myprofits[j];
1507  else
1508  {
1509  SCIP_Real sumprofit;
1510 
1511  if( d - myweights[j] < currminweight )
1512  sumprofit = myprofits[j];
1513  else
1514  sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1515 
1516  optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1517  }
1518  }
1519 
1520  /* update currminweight */
1521  if( intweight < currminweight )
1522  currminweight = intweight;
1523 
1524  allcurrminweight[j] = currminweight;
1525  }
1526 
1527  /* update optimal solution by following the table */
1528  if( solitems != NULL )
1529  {
1530  assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1531  d = intcap - 1;
1532 
1533  SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1534 
1535  /* insert all items in (non-) solution vector */
1536  for( j = nmyitems - 1; j > 0; --j )
1537  {
1538  /* if the following condition holds this means all remaining items does not fit anymore */
1539  if( d < allcurrminweight[j] )
1540  {
1541  /* we cannot have exceeded our capacity */
1542  assert((SCIP_Longint) d >= -minweight);
1543  break;
1544  }
1545 
1546  /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1547  if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1548  {
1549  solitems[(*nsolitems)++] = myitems[j];
1550 
1551  /* check that we do not have an underflow */
1552  assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1553  d = (int)(d - myweights[j]);
1554  }
1555  /* collect non-solution items */
1556  else
1557  nonsolitems[(*nnonsolitems)++] = myitems[j];
1558  }
1559 
1560  /* insert remaining items */
1561  if( d >= allcurrminweight[j] )
1562  {
1563  assert(j == 0);
1564  solitems[(*nsolitems)++] = myitems[j];
1565  }
1566  else
1567  {
1568  assert(j >= 0);
1569  assert(d < allcurrminweight[j]);
1570 
1571  for( ; j >= 0; --j )
1572  nonsolitems[(*nnonsolitems)++] = myitems[j];
1573  }
1574 
1575  assert(*nsolitems + *nnonsolitems == nitems);
1576  }
1577 
1578  /* update solution value */
1579  if( solval != NULL )
1580  *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1581  SCIPfreeBufferArray(scip, &allcurrminweight);
1582 
1583  /* free all temporary memory */
1584  SCIPfreeBufferArray(scip, &optvalues);
1585 
1586  TERMINATE:
1587  SCIPfreeBufferArray(scip, &myitems);
1588  SCIPfreeBufferArray(scip, &myprofits);
1589  SCIPfreeBufferArray(scip, &myweights);
1590 
1591  return SCIP_OKAY;
1592 }
1593 
1594 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1595  * method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1596  * selected items
1597  */
1599  SCIP* scip, /**< SCIP data structure */
1600  int nitems, /**< number of available items */
1601  SCIP_Longint* weights, /**< item weights */
1602  SCIP_Real* profits, /**< item profits */
1603  SCIP_Longint capacity, /**< capacity of knapsack */
1604  int* items, /**< item numbers */
1605  int* solitems, /**< array to store items in solution, or NULL */
1606  int* nonsolitems, /**< array to store items not in solution, or NULL */
1607  int* nsolitems, /**< pointer to store number of items in solution, or NULL */
1608  int* nnonsolitems, /**< pointer to store number of items not in solution, or NULL */
1609  SCIP_Real* solval /**< pointer to store optimal solution value, or NULL */
1610  )
1611 {
1612  SCIP_Real* tempsort;
1613  SCIP_Longint solitemsweight;
1614  SCIP_Real* realweights;
1615  int j;
1616  int criticalindex;
1617 
1618  assert(weights != NULL);
1619  assert(profits != NULL);
1620  assert(capacity >= 0);
1621  assert(items != NULL);
1622  assert(nitems >= 0);
1623 
1624  if( solitems != NULL )
1625  {
1626  *nsolitems = 0;
1627  *nnonsolitems = 0;
1628  }
1629  if( solval != NULL )
1630  *solval = 0.0;
1631 
1632  /* initialize data for median search */
1633  SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1634  SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1635  for( j = nitems - 1; j >= 0; --j )
1636  {
1637  tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1638  realweights[j] = (SCIP_Real)weights[j];
1639  }
1640 
1641  /* partially sort indices such that all elements that are larger than the break item appear first */
1642  SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1643 
1644  /* selects items as long as they fit into the knapsack */
1645  solitemsweight = 0;
1646  for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1647  {
1648  if( solitems != NULL )
1649  solitems[(*nsolitems)++] = items[j];
1650 
1651  if( solval != NULL )
1652  (*solval) += profits[j];
1653  solitemsweight += weights[j];
1654  }
1655  if ( solitems != NULL )
1656  {
1657  for( ; j < nitems; j++ )
1658  nonsolitems[(*nnonsolitems)++] = items[j];
1659  }
1660 
1661  SCIPfreeBufferArray(scip, &realweights);
1662  SCIPfreeBufferArray(scip, &tempsort);
1663 
1664  return SCIP_OKAY;
1665 }
1666 
1667 #ifdef SCIP_DEBUG
1668 /** prints all nontrivial GUB constraints and their LP solution values */
1669 static
1670 void GUBsetPrint(
1671  SCIP* scip, /**< SCIP data structure */
1672  SCIP_GUBSET* gubset, /**< GUB set data structure */
1673  SCIP_VAR** vars, /**< variables in knapsack constraint */
1674  SCIP_Real* solvals /**< solution values of variables in knapsack constraint; or NULL */
1675  )
1676 {
1677  int nnontrivialgubconss;
1678  int c;
1679 
1680  nnontrivialgubconss = 0;
1681 
1682  SCIPdebugMsg(scip, " Nontrivial GUBs of current GUB set:\n");
1683 
1684  /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1685  for( c = 0; c < gubset->ngubconss; c++ )
1686  {
1687  SCIP_Real gubsolval;
1688 
1689  assert(gubset->gubconss[c]->ngubvars >= 0);
1690 
1691  /* nontrivial GUB */
1692  if( gubset->gubconss[c]->ngubvars > 1 )
1693  {
1694  int v;
1695 
1696  gubsolval = 0.0;
1697  SCIPdebugMsg(scip, " GUB<%d>:\n", c);
1698 
1699  /* print GUB var */
1700  for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1701  {
1702  int currentvar;
1703 
1704  currentvar = gubset->gubconss[c]->gubvars[v];
1705  if( solvals != NULL )
1706  {
1707  gubsolval += solvals[currentvar];
1708  SCIPdebugMsg(scip, " +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1709  }
1710  else
1711  {
1712  SCIPdebugMsg(scip, " +<%s>\n", SCIPvarGetName(vars[currentvar]));
1713  }
1714  }
1715 
1716  /* check whether LP solution satisfies the GUB constraint */
1717  if( solvals != NULL )
1718  {
1719  SCIPdebugMsg(scip, " =%4.2f <= 1 %s\n", gubsolval,
1720  SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1721  }
1722  else
1723  {
1724  SCIPdebugMsg(scip, " <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1725  }
1726  nnontrivialgubconss++;
1727  }
1728  }
1729 
1730  SCIPdebugMsg(scip, " --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1731 }
1732 #endif
1733 
1734 /** creates an empty GUB constraint */
1735 static
1737  SCIP* scip, /**< SCIP data structure */
1738  SCIP_GUBCONS** gubcons /**< pointer to store GUB constraint data */
1739  )
1740 {
1741  assert(scip != NULL);
1742  assert(gubcons != NULL);
1743 
1744  /* allocate memory for GUB constraint data structures */
1745  SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1746  (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1747  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1748  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1749 
1750  (*gubcons)->ngubvars = 0;
1751 
1752  return SCIP_OKAY;
1753 }
1754 
1755 /** frees GUB constraint */
1756 static
1757 void GUBconsFree(
1758  SCIP* scip, /**< SCIP data structure */
1759  SCIP_GUBCONS** gubcons /**< pointer to GUB constraint data structure */
1760  )
1761 {
1762  assert(scip != NULL);
1763  assert(gubcons != NULL);
1764  assert((*gubcons)->gubvars != NULL);
1765  assert((*gubcons)->gubvarsstatus != NULL);
1766 
1767  /* free allocated memory */
1768  SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1769  SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1770  SCIPfreeBuffer(scip, gubcons);
1771 }
1772 
1773 /** adds variable to given GUB constraint */
1774 static
1776  SCIP* scip, /**< SCIP data structure */
1777  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1778  int var /**< index of given variable in knapsack constraint */
1779  )
1780 {
1781  assert(scip != NULL);
1782  assert(gubcons != NULL);
1783  assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1784  assert(gubcons->gubvars != NULL);
1785  assert(gubcons->gubvarsstatus != NULL);
1786  assert(var >= 0);
1787 
1788  /* add variable to GUB constraint */
1789  gubcons->gubvars[gubcons->ngubvars] = var;
1790  gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1791  gubcons->ngubvars++;
1792 
1793  /* increase space allocated to GUB constraint if the number of variables reaches the size */
1794  if( gubcons->ngubvars == gubcons->gubvarssize )
1795  {
1796  int newlen;
1797 
1798  newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1799  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1800  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1801 
1802  gubcons->gubvarssize = newlen;
1803  }
1804 
1805  return SCIP_OKAY;
1806 }
1807 
1808 /** deletes variable from its current GUB constraint */
1809 static
1811  SCIP* scip, /**< SCIP data structure */
1812  SCIP_GUBCONS* gubcons, /**< GUB constraint data */
1813  int var, /**< index of given variable in knapsack constraint */
1814  int gubvarsidx /**< index of the variable in its current GUB constraint */
1815  )
1816 {
1817  assert(scip != NULL);
1818  assert(gubcons != NULL);
1819  assert(var >= 0);
1820  assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1821  assert(gubcons->ngubvars >= gubvarsidx+1);
1822  assert(gubcons->gubvars[gubvarsidx] == var);
1823 
1824  /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1825  gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1826  gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1827  gubcons->ngubvars--;
1828 
1829  /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1830  if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1831  {
1832  int newlen;
1833 
1834  newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1835 
1836  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1837  SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1838 
1839  gubcons->gubvarssize = newlen;
1840  }
1841 
1842  return SCIP_OKAY;
1843 }
1844 
1845 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1846 static
1848  SCIP* scip, /**< SCIP data structure */
1849  SCIP_GUBSET* gubset, /**< GUB set data structure */
1850  SCIP_VAR** vars, /**< variables in knapsack constraint */
1851  int var, /**< index of given variable in knapsack constraint */
1852  int oldgubcons, /**< index of old GUB constraint of given variable */
1853  int newgubcons /**< index of new GUB constraint of given variable */
1854  )
1856  int oldgubvaridx;
1857  int replacevar;
1858  int j;
1859 
1860  assert(scip != NULL);
1861  assert(gubset != NULL);
1862  assert(var >= 0);
1863  assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1864  assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1865  assert(oldgubcons != newgubcons);
1866  assert(gubset->gubconssidx[var] == oldgubcons);
1867  assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1868  assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1869 
1870  SCIPdebugMsg(scip, " moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1871 
1872  oldgubvaridx = gubset->gubvarsidx[var];
1873 
1874  /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1875  SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1876 
1877  /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1878  * replacement variable is given by old position of the deleted variable
1879  */
1880  replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1881  assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1882  gubset->gubvarsidx[replacevar] = oldgubvaridx;
1883 
1884  /* add variable to the end of new GUB constraint */
1885  SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1886  assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1887 
1888  /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1889  gubset->gubconssidx[var] = newgubcons;
1890  gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1891 
1892  /* delete old GUB constraint if it became empty */
1893  if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1894  {
1895  SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1896 #ifdef SCIP_DEBUG
1897  GUBsetPrint(scip, gubset, vars, NULL);
1898 #endif
1899 
1900  /* free old GUB constraint */
1901  GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1902 
1903  /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1904  if( oldgubcons != gubset->ngubconss-1 )
1905  {
1906  gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1907  gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1908 
1909  /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1910  * replacement GUB is given by old position of the deleted GUB
1911  */
1912  for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1913  {
1914  assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1915  gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1916  }
1917  }
1918 
1919  /* update number of GUB constraints */
1920  gubset->ngubconss--;
1921 
1922  /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1923  * (because it was at the end of the GUB constraint array)
1924  */
1925  assert(gubset->gubconssidx[var] == newgubcons
1926  || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1927  }
1928 #ifndef NDEBUG
1929  else
1930  assert(gubset->gubconssidx[var] == newgubcons);
1931 #endif
1932 
1933  return SCIP_OKAY;
1934 }
1935 
1936 /** swaps two variables in the same GUB constraint */
1937 static
1938 void GUBsetSwapVars(
1939  SCIP* scip, /**< SCIP data structure */
1940  SCIP_GUBSET* gubset, /**< GUB set data structure */
1941  int var1, /**< first variable to be swapped */
1942  int var2 /**< second variable to be swapped */
1943  )
1944 {
1945  int gubcons;
1946  int var1idx;
1947  GUBVARSTATUS var1status;
1948  int var2idx;
1949  GUBVARSTATUS var2status;
1950 
1951  assert(scip != NULL);
1952  assert(gubset != NULL);
1953 
1954  gubcons = gubset->gubconssidx[var1];
1955  assert(gubcons == gubset->gubconssidx[var2]);
1956 
1957  /* nothing to be done if both variables are the same */
1958  if( var1 == var2 )
1959  return;
1960 
1961  /* swap index and status of variables in GUB constraint */
1962  var1idx = gubset->gubvarsidx[var1];
1963  var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1964  var2idx = gubset->gubvarsidx[var2];
1965  var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1966 
1967  gubset->gubvarsidx[var1] = var2idx;
1968  gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1969  gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1970 
1971  gubset->gubvarsidx[var2] = var1idx;
1972  gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1973  gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1974 }
1975 
1976 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1977 static
1979  SCIP* scip, /**< SCIP data structure */
1980  SCIP_GUBSET** gubset, /**< pointer to store GUB set data structure */
1981  int nvars, /**< number of variables in the knapsack constraint */
1982  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
1983  SCIP_Longint capacity /**< capacity of knapsack */
1984  )
1985 {
1986  int i;
1987 
1988  assert(scip != NULL);
1989  assert(gubset != NULL);
1990  assert(nvars > 0);
1991  assert(weights != NULL);
1992  assert(capacity >= 0);
1993 
1994  /* allocate memory for GUB set data structures */
1995  SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1996  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1997  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1998  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1999  SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
2000  (*gubset)->ngubconss = nvars;
2001  (*gubset)->nvars = nvars;
2002 
2003  /* initialize the set of GUB constraints */
2004  for( i = 0; i < nvars; i++ )
2005  {
2006  /* assign each variable to a new (trivial) GUB constraint */
2007  SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
2008  SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
2009 
2010  /* set status of GUB constraint to initial */
2011  (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
2012 
2013  (*gubset)->gubconssidx[i] = i;
2014  (*gubset)->gubvarsidx[i] = 0;
2015  assert((*gubset)->gubconss[i]->ngubvars == 1);
2016 
2017  /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
2018  if( weights[i] > capacity )
2019  (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
2020  }
2021 
2022  return SCIP_OKAY;
2023 }
2024 
2025 /** frees GUB set data structure */
2026 static
2027 void GUBsetFree(
2028  SCIP* scip, /**< SCIP data structure */
2029  SCIP_GUBSET** gubset /**< pointer to GUB set data structure */
2030  )
2031 {
2032  int i;
2033 
2034  assert(scip != NULL);
2035  assert(gubset != NULL);
2036  assert((*gubset)->gubconss != NULL);
2037  assert((*gubset)->gubconsstatus != NULL);
2038  assert((*gubset)->gubconssidx != NULL);
2039  assert((*gubset)->gubvarsidx != NULL);
2040 
2041  /* free all GUB constraints */
2042  for( i = (*gubset)->ngubconss-1; i >= 0; --i )
2043  {
2044  assert((*gubset)->gubconss[i] != NULL);
2045  GUBconsFree(scip, &(*gubset)->gubconss[i]);
2046  }
2047 
2048  /* free allocated memory */
2049  SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
2050  SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
2051  SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
2052  SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
2053  SCIPfreeBuffer(scip, gubset);
2054 }
2055 
2056 #ifndef NDEBUG
2057 /** checks whether GUB set data structure is consistent */
2058 static
2060  SCIP* scip, /**< SCIP data structure */
2061  SCIP_GUBSET* gubset, /**< GUB set data structure */
2062  SCIP_VAR** vars /**< variables in the knapsack constraint */
2063  )
2064 {
2065  int i;
2066  int gubconsidx;
2067  int gubvaridx;
2068  SCIP_VAR* var1;
2069  SCIP_VAR* var2;
2070  SCIP_Bool var1negated;
2071  SCIP_Bool var2negated;
2072 
2073  assert(scip != NULL);
2074  assert(gubset != NULL);
2075 
2076  SCIPdebugMsg(scip, " GUB set consistency check:\n");
2077 
2078  /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2079  for( i = 0; i < gubset->nvars; i++ )
2080  {
2081  gubconsidx = gubset->gubconssidx[i];
2082  gubvaridx = gubset->gubvarsidx[i];
2083 
2084  if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2085  {
2086  SCIPdebugMsg(scip, " var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2087  gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2088  }
2089  assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2090  }
2091 
2092  /* checks for each GUB whether all pairs of its variables have a common clique */
2093  for( i = 0; i < gubset->ngubconss; i++ )
2094  {
2095  int j;
2096 
2097  for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2098  {
2099  int k;
2100 
2101  /* get corresponding active problem variable */
2102  var1 = vars[gubset->gubconss[i]->gubvars[j]];
2103  var1negated = FALSE;
2104  SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2105 
2106  for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2107  {
2108  /* get corresponding active problem variable */
2109  var2 = vars[gubset->gubconss[i]->gubvars[k]];
2110  var2negated = FALSE;
2111  SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2112 
2113  if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2114  {
2115  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2116  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2117  SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2118  SCIPdebugMsg(scip, " GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2119  SCIPvarGetName(var1), k,
2120  SCIPvarGetName(var2));
2121  }
2122 
2123  /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2124  assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2125  }
2126  }
2127  }
2128  SCIPdebugMsg(scip, " --> successful\n");
2129 
2130  return SCIP_OKAY;
2131 }
2132 #endif
2133 
2134 /** calculates a partition of the given set of binary variables into cliques;
2135  * afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2136  * were assigned to the same clique;
2137  * the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2138  * the preceding variables was assigned to clique i-1;
2139  * note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2140  * variable) and for the remaining variables, a partition with a small number of cliques is constructed
2141  */
2142 
2143 static
2145  SCIP*const scip, /**< SCIP data structure */
2146  SCIP_VAR**const vars, /**< binary variables in the clique from which at most one can be set to 1 */
2147  int const nvars, /**< number of variables in the clique */
2148  int*const cliquepartition, /**< array of length nvars to store the clique partition */
2149  int*const ncliques, /**< pointer to store number of cliques actually contained in the partition */
2150  SCIP_Real* solvals /**< solution values of all given binary variables */
2151  )
2153  SCIP_VAR** tmpvars;
2154  SCIP_VAR** cliquevars;
2155  SCIP_Bool* cliquevalues;
2156  SCIP_Bool* tmpvalues;
2157  int* varseq;
2158  int* sortkeys;
2159  int ncliquevars;
2160  int maxncliquevarscomp;
2161  int nignorevars;
2162  int nvarsused;
2163  int i;
2164 
2165  assert(scip != NULL);
2166  assert(nvars == 0 || vars != NULL);
2167  assert(nvars == 0 || cliquepartition != NULL);
2168  assert(ncliques != NULL);
2169 
2170  if( nvars == 0 )
2171  {
2172  *ncliques = 0;
2173  return SCIP_OKAY;
2174  }
2175 
2176  /* allocate temporary memory for storing the variables of the current clique */
2177  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2178  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2179  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2180  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2181  SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2182  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2183 
2184  /* initialize the cliquepartition array with -1 */
2185  /* initialize the tmpvalues array */
2186  for( i = nvars - 1; i >= 0; --i )
2187  {
2188  tmpvalues[i] = TRUE;
2189  cliquepartition[i] = -1;
2190  }
2191 
2192  /* get corresponding active problem variables */
2193  SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2194 
2195  /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2196  * by nondecreasing number of cliques the variables are in
2197  */
2198  nignorevars = 0;
2199  nvarsused = 0;
2200  for( i = 0; i < nvars; i++ )
2201  {
2202  if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2203  {
2204  /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2205  varseq[nvars-1-nignorevars] = i;
2206  nignorevars++;
2207  }
2208  else
2209  {
2210  /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2211  varseq[nvarsused] = i;
2212  sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2213  nvarsused++;
2214  }
2215  }
2216  assert(nvarsused + nignorevars == nvars);
2217 
2218  /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2219  SCIPsortIntInt(sortkeys, varseq, nvarsused);
2220 
2221  maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2222 
2223  /* calculate the clique partition */
2224  *ncliques = 0;
2225  for( i = 0; i < nvars; ++i )
2226  {
2227  if( cliquepartition[varseq[i]] == -1 )
2228  {
2229  int j;
2230 
2231  /* variable starts a new clique */
2232  cliquepartition[varseq[i]] = *ncliques;
2233  cliquevars[0] = tmpvars[varseq[i]];
2234  cliquevalues[0] = tmpvalues[varseq[i]];
2235  ncliquevars = 1;
2236 
2237  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2238  * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2239  */
2240  if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2241  {
2242  /* greedily fill up the clique */
2243  for( j = i + 1; j < nvarsused; ++j )
2244  {
2245  /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2246  if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2247  {
2248  int k;
2249 
2250  /* check if every variable in the actual clique is in clique with the new variable */
2251  for( k = ncliquevars - 1; k >= 0; --k )
2252  {
2253  if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2254  cliquevalues[k], TRUE) )
2255  break;
2256  }
2257 
2258  if( k == -1 )
2259  {
2260  /* put the variable into the same clique */
2261  cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2262  cliquevars[ncliquevars] = tmpvars[varseq[j]];
2263  cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2264  ++ncliquevars;
2265  }
2266  }
2267  }
2268  }
2269 
2270  /* this clique is finished */
2271  ++(*ncliques);
2272  }
2273  assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2274 
2275  /* break if we reached the maximal number of comparisons */
2276  if( i * nvars > maxncliquevarscomp )
2277  break;
2278  }
2279  /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2280  for( ; i < nvars; ++i )
2281  {
2282  if( cliquepartition[varseq[i]] == -1 )
2283  {
2284  cliquepartition[varseq[i]] = *ncliques;
2285  ++(*ncliques);
2286  }
2287  }
2288 
2289  /* free temporary memory */
2290  SCIPfreeBufferArray(scip, &sortkeys);
2291  SCIPfreeBufferArray(scip, &varseq);
2292  SCIPfreeBufferArray(scip, &tmpvars);
2293  SCIPfreeBufferArray(scip, &tmpvalues);
2294  SCIPfreeBufferArray(scip, &cliquevalues);
2295  SCIPfreeBufferArray(scip, &cliquevars);
2296 
2297  return SCIP_OKAY;
2298 }
2299 
2300 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2301 static
2303  SCIP* scip, /**< SCIP data structure */
2304  SCIP_GUBSET* gubset, /**< GUB set data structure */
2305  SCIP_VAR** vars, /**< variables in the knapsack constraint */
2306  SCIP_Real* solvals /**< solution values of all knapsack variables */
2307  )
2308 {
2309  int* cliquepartition;
2310  int* gubfirstvar;
2311  int ncliques;
2312  int currentgubconsidx;
2313  int newgubconsidx;
2314  int cliqueidx;
2315  int nvars;
2316  int i;
2317 
2318  assert(scip != NULL);
2319  assert(gubset != NULL);
2320  assert(vars != NULL);
2321 
2322  nvars = gubset->nvars;
2323  assert(nvars >= 0);
2324 
2325  /* allocate temporary memory for clique partition */
2326  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2327 
2328  /* compute sophisticated clique partition */
2329  SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2330 
2331  /* allocate temporary memory for GUB set data structure */
2332  SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2333 
2334  /* translate GUB partition into GUB set data structure */
2335  for( i = 0; i < ncliques; i++ )
2336  {
2337  /* initialize first variable for every GUB */
2338  gubfirstvar[i] = -1;
2339  }
2340  /* move every knapsack variable into GUB defined by clique partition */
2341  for( i = 0; i < nvars; i++ )
2342  {
2343  assert(cliquepartition[i] >= 0);
2344 
2345  cliqueidx = cliquepartition[i];
2346  currentgubconsidx = gubset->gubconssidx[i];
2347  assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2348 
2349  /* variable is first element in GUB constraint defined by clique partition */
2350  if( gubfirstvar[cliqueidx] == -1 )
2351  {
2352  /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2353  * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2354  */
2355  assert(gubset->gubvarsidx[i] == 0);
2356  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2357 
2358  /* remember the first variable found for the current GUB */
2359  gubfirstvar[cliqueidx] = i;
2360  }
2361  /* variable is additional element of GUB constraint defined by clique partition */
2362  else
2363  {
2364  assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2365 
2366  /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2367  * first variable of this GUB constraint
2368  */
2369  newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2370  assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2371  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2372 
2373  assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2374  }
2375  }
2376 
2377 #ifdef SCIP_DEBUG
2378  /* prints GUB set data structure */
2379  GUBsetPrint(scip, gubset, vars, solvals);
2380 #endif
2381 
2382 #ifndef NDEBUG
2383  /* checks consistency of GUB set data structure */
2384  SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2385 #endif
2386 
2387  /* free temporary memory */
2388  SCIPfreeBufferArray(scip, &gubfirstvar);
2389  SCIPfreeBufferArray(scip, &cliquepartition);
2390 
2391  return SCIP_OKAY;
2392 }
2393 
2394 /** 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$
2395  * 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
2396  * \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2397  */
2398 static
2400  SCIP* scip, /**< SCIP data structure */
2401  SCIP_VAR** vars, /**< variables in knapsack constraint */
2402  int nvars, /**< number of variables in knapsack constraint */
2403  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2404  SCIP_Longint capacity, /**< capacity of knapsack */
2405  SCIP_Real* solvals, /**< solution values of all problem variables */
2406  int* covervars, /**< pointer to store cover variables */
2407  int* noncovervars, /**< pointer to store noncover variables */
2408  int* ncovervars, /**< pointer to store number of cover variables */
2409  int* nnoncovervars, /**< pointer to store number of noncover variables */
2410  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
2411  SCIP_Bool* found, /**< pointer to store whether a cover was found */
2412  SCIP_Bool modtransused, /**< should modified transformed separation problem be used to find cover */
2413  int* ntightened, /**< pointer to store number of variables with tightened upper bound */
2414  SCIP_Bool* fractional /**< pointer to store whether the LP sol for knapsack vars is fractional */
2415  )
2416 {
2417  SCIP_Longint* transweights;
2418  SCIP_Real* transprofits;
2419  SCIP_Longint transcapacity;
2420  SCIP_Longint fixedonesweight;
2421  SCIP_Longint itemsweight;
2422  SCIP_Bool infeasible;
2423  int* fixedones;
2424  int* fixedzeros;
2425  int* items;
2426  int nfixedones;
2427  int nfixedzeros;
2428  int nitems;
2429  int j;
2430 
2431  assert(scip != NULL);
2432  assert(vars != NULL);
2433  assert(nvars > 0);
2434  assert(weights != NULL);
2435  assert(capacity >= 0);
2436  assert(solvals != NULL);
2437  assert(covervars != NULL);
2438  assert(noncovervars != NULL);
2439  assert(ncovervars != NULL);
2440  assert(nnoncovervars != NULL);
2441  assert(coverweight != NULL);
2442  assert(found != NULL);
2443  assert(ntightened != NULL);
2444  assert(fractional != NULL);
2445 
2446  SCIPdebugMsg(scip, " get cover for knapsack constraint\n");
2447 
2448  /* allocates temporary memory */
2449  SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2450  SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2451  SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2452  SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2453  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2454 
2455  *found = FALSE;
2456  *ncovervars = 0;
2457  *nnoncovervars = 0;
2458  *coverweight = 0;
2459  *fractional = TRUE;
2460 
2461  /* gets the following sets
2462  * N_1 = {j in N : x*_j = 1} (fixedones),
2463  * N_0 = {j in N : x*_j = 0} (fixedzeros) and
2464  * N\(N_0 & N_1) (items),
2465  * where x*_j is the solution value of variable x_j
2466  */
2467  nfixedones = 0;
2468  nfixedzeros = 0;
2469  nitems = 0;
2470  fixedonesweight = 0;
2471  itemsweight = 0;
2472  *ntightened = 0;
2473  for( j = 0; j < nvars; j++ )
2474  {
2475  assert(SCIPvarIsBinary(vars[j]));
2476 
2477  /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2478  if( weights[j] > capacity )
2479  {
2480  SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2481  assert(!infeasible);
2482  (*ntightened)++;
2483  continue;
2484  }
2485 
2486  /* variable x_j has solution value one */
2487  if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2488  {
2489  fixedones[nfixedones] = j;
2490  nfixedones++;
2491  fixedonesweight += weights[j];
2492  }
2493  /* variable x_j has solution value zero */
2494  else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2495  {
2496  fixedzeros[nfixedzeros] = j;
2497  nfixedzeros++;
2498  }
2499  /* variable x_j has fractional solution value */
2500  else
2501  {
2502  assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2503  items[nitems] = j;
2504  nitems++;
2505  itemsweight += weights[j];
2506  }
2507  }
2508  assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2509 
2510  /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2511  * the separation routine
2512  */
2513  assert(nitems >= 0);
2514  if( nitems == 0 )
2515  {
2516  *fractional = FALSE;
2517  goto TERMINATE;
2518  }
2519  assert(*fractional);
2520 
2521  /* transforms the traditional separation problem (under consideration of the following fixing:
2522  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2523  *
2524  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2525  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2526  * z_j in {0,1}, j in N\(N_0 & N_1)
2527  *
2528  * to a knapsack problem in maximization form by complementing the variables
2529  *
2530  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2531  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2532  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2533  * z_j in {0,1}, j in N\(N_0 & N_1)
2534  */
2535 
2536  /* gets weight and profit of variables in transformed knapsack problem */
2537  for( j = 0; j < nitems; j++ )
2538  {
2539  transweights[j] = weights[items[j]];
2540  transprofits[j] = 1.0 - solvals[items[j]];
2541  }
2542  /* gets capacity of transformed knapsack problem */
2543  transcapacity = fixedonesweight + itemsweight - capacity - 1;
2544 
2545  /* if capacity of transformed knapsack problem is less than zero, there is no cover
2546  * (when variables fixed to zero are not used)
2547  */
2548  if( transcapacity < 0 )
2549  {
2550  assert(!(*found));
2551  goto TERMINATE;
2552  }
2553 
2554  if( modtransused )
2555  {
2556  /* transforms the modified separation problem (under consideration of the following fixing:
2557  * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2558  *
2559  * min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2560  * sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2561  * z_j in {0,1}, j in N\(N_0 & N_1)
2562  *
2563  * to a knapsack problem in maximization form by complementing the variables
2564  *
2565  * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2566  * max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2567  * sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2568  * z_j in {0,1}, j in N\(N_0 & N_1)
2569  */
2570 
2571  /* gets weight and profit of variables in modified transformed knapsack problem */
2572  for( j = 0; j < nitems; j++ )
2573  {
2574  transprofits[j] *= weights[items[j]];
2575  assert(SCIPisFeasPositive(scip, transprofits[j]));
2576  }
2577  }
2578 
2579  /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2580  * transformed knapsack problem using Dantzig's method and rounding down the solution.
2581  * let z* be the solution, then
2582  * j in C, if z*_j = 0 and
2583  * i in N\C, if z*_j = 1.
2584  */
2585  SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2586  noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2587  /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2588 
2589  /* constructs cover C (sum_{j in C} a_j > a_0) */
2590  for( j = 0; j < *ncovervars; j++ )
2591  {
2592  (*coverweight) += weights[covervars[j]];
2593  }
2594 
2595  /* adds all variables from N_1 to C */
2596  for( j = 0; j < nfixedones; j++ )
2597  {
2598  covervars[*ncovervars] = fixedones[j];
2599  (*ncovervars)++;
2600  (*coverweight) += weights[fixedones[j]];
2601  }
2602 
2603  /* adds all variables from N_0 to N\C */
2604  for( j = 0; j < nfixedzeros; j++ )
2605  {
2606  noncovervars[*nnoncovervars] = fixedzeros[j];
2607  (*nnoncovervars)++;
2608  }
2609  assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2610  assert((*coverweight) > capacity);
2611  *found = TRUE;
2612 
2613  TERMINATE:
2614  /* frees temporary memory */
2615  SCIPfreeBufferArray(scip, &items);
2616  SCIPfreeBufferArray(scip, &fixedzeros);
2617  SCIPfreeBufferArray(scip, &fixedones);
2618  SCIPfreeBufferArray(scip, &transprofits);
2619  SCIPfreeBufferArray(scip, &transweights);
2620 
2621  SCIPdebugMsg(scip, " get cover for knapsack constraint -- end\n");
2622 
2623  return SCIP_OKAY;
2624 }
2625 
2626 #ifndef NDEBUG
2627 /** checks if minweightidx is set correctly
2628  */
2629 static
2631  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2632  SCIP_Longint capacity, /**< capacity of knapsack */
2633  int* covervars, /**< pointer to store cover variables */
2634  int ncovervars, /**< pointer to store number of cover variables */
2635  SCIP_Longint coverweight, /**< pointer to store weight of cover */
2636  int minweightidx, /**< index of variable in cover variables with minimum weight */
2637  int j /**< current index in cover variables */
2638  )
2639 {
2640  SCIP_Longint minweight;
2641  int i;
2642 
2643  assert(weights != NULL);
2644  assert(covervars != NULL);
2645  assert(ncovervars > 0);
2646 
2647  minweight = weights[covervars[minweightidx]];
2648 
2649  /* checks if all cover variables before index j have weight greater than minweight */
2650  for( i = 0; i < j; i++ )
2651  {
2652  assert(weights[covervars[i]] > minweight);
2653  if( weights[covervars[i]] <= minweight )
2654  return FALSE;
2655  }
2656 
2657  /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2658  for( i = 0; i < j; i++ )
2659  {
2660  assert(coverweight - weights[covervars[i]] <= capacity);
2661  if( coverweight - weights[covervars[i]] > capacity )
2662  return FALSE;
2663  }
2664  return TRUE;
2665 }
2666 #endif
2667 
2668 
2669 /** 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$,
2670  * 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$
2671  */
2672 static
2674  SCIP* scip, /**< SCIP data structure */
2675  SCIP_Real* solvals, /**< solution values of all problem variables */
2676  int* covervars, /**< cover variables */
2677  int ncovervars, /**< number of cover variables */
2678  int* varsC1, /**< pointer to store variables in C1 */
2679  int* varsC2, /**< pointer to store variables in C2 */
2680  int* nvarsC1, /**< pointer to store number of variables in C1 */
2681  int* nvarsC2 /**< pointer to store number of variables in C2 */
2682  )
2683 {
2684  int j;
2685 
2686  assert(scip != NULL);
2687  assert(ncovervars >= 0);
2688  assert(solvals != NULL);
2689  assert(covervars != NULL);
2690  assert(varsC1 != NULL);
2691  assert(varsC2 != NULL);
2692  assert(nvarsC1 != NULL);
2693  assert(nvarsC2 != NULL);
2694 
2695  *nvarsC1 = 0;
2696  *nvarsC2 = 0;
2697  for( j = 0; j < ncovervars; j++ )
2698  {
2699  assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2700 
2701  /* variable has solution value one */
2702  if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2703  {
2704  varsC2[*nvarsC2] = covervars[j];
2705  (*nvarsC2)++;
2706  }
2707  /* variable has solution value less than one */
2708  else
2709  {
2710  assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2711  varsC1[*nvarsC1] = covervars[j];
2712  (*nvarsC1)++;
2713  }
2714  }
2715  assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2716 }
2717 
2718 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2719  * C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2720  */
2721 static
2723  SCIP* scip, /**< SCIP data structure */
2724  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2725  int* varsC1, /**< pointer to store variables in C1 */
2726  int* varsC2, /**< pointer to store variables in C2 */
2727  int* nvarsC1, /**< pointer to store number of variables in C1 */
2728  int* nvarsC2 /**< pointer to store number of variables in C2 */
2729  )
2731  SCIP_Real* sortkeysC2;
2732  int j;
2733 
2734  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2735  assert(*nvarsC2 > 0);
2736 
2737  /* allocates temporary memory */
2738  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2739 
2740  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2741  for( j = 0; j < *nvarsC2; j++ )
2742  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2743  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2744 
2745  /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2746  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2747  while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2748  {
2749  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2750  (*nvarsC1)++;
2751  (*nvarsC2)--;
2752  }
2753 
2754  /* frees temporary memory */
2755  SCIPfreeBufferArray(scip, &sortkeysC2);
2756 
2757  return SCIP_OKAY;
2758 }
2759 
2760 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2761 static
2763  SCIP* scip, /**< SCIP data structure */
2764  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2765  int* varsC1, /**< pointer to store variables in C1 */
2766  int* varsC2, /**< pointer to store variables in C2 */
2767  int* nvarsC1, /**< pointer to store number of variables in C1 */
2768  int* nvarsC2 /**< pointer to store number of variables in C2 */
2769  )
2771  SCIP_Real* sortkeysC2;
2772  int j;
2773 
2774  assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2775  assert(*nvarsC2 > 0);
2776 
2777  /* allocates temporary memory */
2778  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2779 
2780  /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2781  for( j = 0; j < *nvarsC2; j++ )
2782  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2783  SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2784 
2785  /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2786  assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2787  varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2788  (*nvarsC1)++;
2789  (*nvarsC2)--;
2790 
2791  /* frees temporary memory */
2792  SCIPfreeBufferArray(scip, &sortkeysC2);
2793 
2794  return SCIP_OKAY;
2795 }
2796 
2797 
2798 /** 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$
2799  * and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2800  * \f$F = (N \setminus C) \setminus F\f$
2801  */
2802 static
2804  SCIP* scip, /**< SCIP data structure */
2805  SCIP_Real* solvals, /**< solution values of all problem variables */
2806  int* noncovervars, /**< noncover variables */
2807  int nnoncovervars, /**< number of noncover variables */
2808  int* varsF, /**< pointer to store variables in F */
2809  int* varsR, /**< pointer to store variables in R */
2810  int* nvarsF, /**< pointer to store number of variables in F */
2811  int* nvarsR /**< pointer to store number of variables in R */
2812  )
2813 {
2814  int j;
2815 
2816  assert(scip != NULL);
2817  assert(nnoncovervars >= 0);
2818  assert(solvals != NULL);
2819  assert(noncovervars != NULL);
2820  assert(varsF != NULL);
2821  assert(varsR != NULL);
2822  assert(nvarsF != NULL);
2823  assert(nvarsR != NULL);
2824 
2825  *nvarsF = 0;
2826  *nvarsR = 0;
2827 
2828  for( j = 0; j < nnoncovervars; j++ )
2829  {
2830  /* variable has solution value zero */
2831  if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2832  {
2833  varsR[*nvarsR] = noncovervars[j];
2834  (*nvarsR)++;
2835  }
2836  /* variable has solution value greater than zero */
2837  else
2838  {
2839  assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2840  varsF[*nvarsF] = noncovervars[j];
2841  (*nvarsF)++;
2842  }
2843  }
2844  assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2845 }
2846 
2847 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2848  * lifting procedure
2849  */
2850 static
2852  SCIP* scip, /**< SCIP data structure */
2853  SCIP_Real* solvals, /**< solution values of all problem variables */
2854  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2855  int* varsF, /**< pointer to store variables in F */
2856  int* varsC2, /**< pointer to store variables in C2 */
2857  int* varsR, /**< pointer to store variables in R */
2858  int nvarsF, /**< number of variables in F */
2859  int nvarsC2, /**< number of variables in C2 */
2860  int nvarsR /**< number of variables in R */
2861  )
2862 {
2863  SORTKEYPAIR** sortkeypairsF;
2864  SORTKEYPAIR* sortkeypairsFstore;
2865  SCIP_Real* sortkeysC2;
2866  SCIP_Real* sortkeysR;
2867  int j;
2868 
2869  assert(scip != NULL);
2870  assert(solvals != NULL);
2871  assert(weights != NULL);
2872  assert(varsF != NULL);
2873  assert(varsC2 != NULL);
2874  assert(varsR != NULL);
2875  assert(nvarsF >= 0);
2876  assert(nvarsC2 >= 0);
2877  assert(nvarsR >= 0);
2878 
2879  /* allocates temporary memory */
2880  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2881  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2882  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2883  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2884 
2885  /* gets sorting key for variables in F corresponding to the following lifting sequence
2886  * sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2887  * x*_1 >= x*_2 >= ... >= x*_|F|
2888  * in case of equality uses
2889  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2890  */
2891  for( j = 0; j < nvarsF; j++ )
2892  {
2893  sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2894  sortkeypairsF[j]->key1 = solvals[varsF[j]];
2895  sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2896  }
2897 
2898  /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2899  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2900  */
2901  for( j = 0; j < nvarsC2; j++ )
2902  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2903 
2904  /* gets sorting key for variables in R corresponding to the following lifting sequence
2905  * sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2906  */
2907  for( j = 0; j < nvarsR; j++ )
2908  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2909 
2910  /* sorts F, C2 and R */
2911  if( nvarsF > 0 )
2912  {
2913  SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2914  }
2915  if( nvarsC2 > 0 )
2916  {
2917  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2918  }
2919  if( nvarsR > 0)
2920  {
2921  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2922  }
2923 
2924  /* frees temporary memory */
2925  SCIPfreeBufferArray(scip, &sortkeysR);
2926  SCIPfreeBufferArray(scip, &sortkeysC2);
2927  SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2928  SCIPfreeBufferArray(scip, &sortkeypairsF);
2929 
2930  return SCIP_OKAY;
2931 }
2932 
2933 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2934  * for the sequential GUB wise lifting procedure
2935  */
2936 static
2938  SCIP* scip, /**< SCIP data structure */
2939  SCIP_GUBSET* gubset, /**< GUB set data structure */
2940  SCIP_Real* solvals, /**< solution values of variables in knapsack constraint */
2941  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
2942  int* varsC1, /**< variables in C1 */
2943  int* varsC2, /**< variables in C2 */
2944  int* varsF, /**< variables in F */
2945  int* varsR, /**< variables in R */
2946  int nvarsC1, /**< number of variables in C1 */
2947  int nvarsC2, /**< number of variables in C2 */
2948  int nvarsF, /**< number of variables in F */
2949  int nvarsR, /**< number of variables in R */
2950  int* gubconsGC1, /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2951  int* gubconsGC2, /**< pointer to store GUBs in GC2 */
2952  int* gubconsGFC1, /**< pointer to store GUBs in GFC1(GNC1+GF) */
2953  int* gubconsGR, /**< pointer to store GUBs in GR */
2954  int* ngubconsGC1, /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2955  int* ngubconsGC2, /**< pointer to store number of GUBs in GC2 */
2956  int* ngubconsGFC1, /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2957  int* ngubconsGR, /**< pointer to store number of GUBs in GR */
2958  int* ngubconscapexceed, /**< pointer to store number of GUBs with only capacity exceeding variables */
2959  int* maxgubvarssize /**< pointer to store the maximal size of GUB constraints */
2960  )
2961 {
2962  SORTKEYPAIR** sortkeypairsGFC1;
2963  SORTKEYPAIR* sortkeypairsGFC1store;
2964  SCIP_Real* sortkeysC1;
2965  SCIP_Real* sortkeysC2;
2966  SCIP_Real* sortkeysR;
2967  int* nC1varsingubcons;
2968  int var;
2969  int gubconsidx;
2970  int varidx;
2971  int ngubconss;
2972  int ngubconsGOC1;
2973  int targetvar;
2974 #ifndef NDEBUG
2975  int nvarsprocessed = 0;
2976 #endif
2977  int i;
2978  int j;
2979 
2980 #if GUBSPLITGNC1GUBS
2981  SCIP_Bool gubconswithF;
2982  int origngubconss;
2983  origngubconss = gubset->ngubconss;
2984 #endif
2985 
2986  assert(scip != NULL);
2987  assert(gubset != NULL);
2988  assert(solvals != NULL);
2989  assert(weights != NULL);
2990  assert(varsC1 != NULL);
2991  assert(varsC2 != NULL);
2992  assert(varsF != NULL);
2993  assert(varsR != NULL);
2994  assert(nvarsC1 > 0);
2995  assert(nvarsC2 >= 0);
2996  assert(nvarsF >= 0);
2997  assert(nvarsR >= 0);
2998  assert(gubconsGC1 != NULL);
2999  assert(gubconsGC2 != NULL);
3000  assert(gubconsGFC1 != NULL);
3001  assert(gubconsGR != NULL);
3002  assert(ngubconsGC1 != NULL);
3003  assert(ngubconsGC2 != NULL);
3004  assert(ngubconsGFC1 != NULL);
3005  assert(ngubconsGR != NULL);
3006  assert(maxgubvarssize != NULL);
3007 
3008  ngubconss = gubset->ngubconss;
3009  ngubconsGOC1 = 0;
3010 
3011  /* GUBs are categorized into different types according to the variables in volved
3012  * - GOC1: involves variables in C1 only -- no C2, R, F
3013  * - GNC1: involves variables in C1 and F (and R) -- no C2
3014  * - GF: involves variables in F (and R) only -- no C1, C2
3015  * - GC2: involves variables in C2 only -- no C1, R, F
3016  * - GR: involves variables in R only -- no C1, C2, F
3017  * which requires splitting GUBs in case they include variable in F and R.
3018  *
3019  * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
3020  * - first ordering level is: GFC1 (GNC1+GF), GC2, and GR.
3021  * - second ordering level is
3022  * GFC1: non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
3023  * GC2: non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
3024  * GR: non-increasing max{ a_k : k in GR_j}
3025  *
3026  * in additon, another GUB union, which is helpful for the lifting procedure, is formed
3027  * - GC1: GUBs of category GOC1 and GNC1
3028  * with second ordering level non-decreasing min{ a_k : k in GC1_j };
3029  * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
3030  */
3031 
3032  /* allocates temporary memory */
3033  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
3034  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
3035  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
3036 
3037  /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
3038  * - F: non-increasing x*_j and non-increasing a_j in case of equality
3039  * - C2: non-increasing a_j
3040  * - R: non-increasing a_j
3041  * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
3042  */
3043 
3044  /* gets sorting key for variables in C1 corresponding to the following ordering
3045  * non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
3046  */
3047  for( j = 0; j < nvarsC1; j++ )
3048  {
3049  /* gets sortkeys */
3050  sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
3051 
3052  /* update status of variable in its gub constraint */
3053  gubconsidx = gubset->gubconssidx[varsC1[j]];
3054  varidx = gubset->gubvarsidx[varsC1[j]];
3055  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
3056  }
3057 
3058  /* gets sorting key for variables in F corresponding to the following ordering
3059  * non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3060  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|F| in case of equality
3061  * and updates status of each variable in F in GUB set data structure
3062  */
3063  for( j = 0; j < nvarsF; j++ )
3064  {
3065  /* update status of variable in its gub constraint */
3066  gubconsidx = gubset->gubconssidx[varsF[j]];
3067  varidx = gubset->gubvarsidx[varsF[j]];
3068  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3069  }
3070 
3071  /* gets sorting key for variables in C2 corresponding to the following ordering
3072  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|C2|
3073  * and updates status of each variable in F in GUB set data structure
3074  */
3075  for( j = 0; j < nvarsC2; j++ )
3076  {
3077  /* gets sortkeys */
3078  sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3079 
3080  /* update status of variable in its gub constraint */
3081  gubconsidx = gubset->gubconssidx[varsC2[j]];
3082  varidx = gubset->gubvarsidx[varsC2[j]];
3083  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3084  }
3085 
3086  /* gets sorting key for variables in R corresponding to the following ordering
3087  * non-increasing a_j, i.e., a_1 >= a_2 >= ... >= a_|R|
3088  * and updates status of each variable in F in GUB set data structure
3089  */
3090  for( j = 0; j < nvarsR; j++ )
3091  {
3092  /* gets sortkeys */
3093  sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3094 
3095  /* update status of variable in its gub constraint */
3096  gubconsidx = gubset->gubconssidx[varsR[j]];
3097  varidx = gubset->gubvarsidx[varsR[j]];
3098  gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3099  }
3100 
3101  /* sorts C1, F, C2 and R */
3102  assert(nvarsC1 > 0);
3103  SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3104 
3105  if( nvarsC2 > 0 )
3106  {
3107  SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3108  }
3109  if( nvarsR > 0)
3110  {
3111  SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3112  }
3113 
3114  /* frees temporary memory */
3115  SCIPfreeBufferArray(scip, &sortkeysR);
3116  SCIPfreeBufferArray(scip, &sortkeysC2);
3117  SCIPfreeBufferArray(scip, &sortkeysC1);
3118 
3119  /* allocate and initialize temporary memory for sorting GUB constraints */
3120  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3121  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3122  SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3123  BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3124  for( i = 0; i < ngubconss; i++)
3125  {
3126  sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3127  sortkeypairsGFC1[i]->key1 = 0.0;
3128  sortkeypairsGFC1[i]->key2 = 0.0;
3129  }
3130  *ngubconsGC1 = 0;
3131  *ngubconsGC2 = 0;
3132  *ngubconsGFC1 = 0;
3133  *ngubconsGR = 0;
3134  *ngubconscapexceed = 0;
3135  *maxgubvarssize = 0;
3136 
3137 #ifndef NDEBUG
3138  for( i = 0; i < gubset->ngubconss; i++ )
3139  assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3140 #endif
3141 
3142  /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3143  * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3144  * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3145  * non-increasing number of variables in F, and
3146  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3147  */
3148  for( i = 0; i < nvarsC1; i++ )
3149  {
3150  int nvarsC1capexceed;
3151 
3152  nvarsC1capexceed = 0;
3153 
3154  var = varsC1[i];
3155  gubconsidx = gubset->gubconssidx[var];
3156  varidx = gubset->gubvarsidx[var];
3157 
3158  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3159  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3160 
3161  /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3162  * note that variables in C1 are already sorted by non-decreasing weigth
3163  */
3164  targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3165  GUBsetSwapVars(scip, gubset, var, targetvar);
3166  nC1varsingubcons[gubconsidx]++;
3167 
3168  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3169  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3170  {
3171  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3172  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3173  continue;
3174  }
3175 
3176  /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3177  * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3178  */
3179 #if GUBSPLITGNC1GUBS
3180  gubconswithF = FALSE;
3181 #endif
3182  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3183  {
3184  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3185 
3186  /* C1-variable: update number of C1/capacity exceeding variables */
3187  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3188  {
3189  nvarsC1capexceed++;
3190 #ifndef NDEBUG
3191  nvarsprocessed++;
3192 #endif
3193  }
3194  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3195  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3196  {
3197 #if GUBSPLITGNC1GUBS
3198  gubconswithF = TRUE;
3199 #endif
3200  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3201 
3202  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3203  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3204  }
3205  else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3206  {
3207  nvarsC1capexceed++;
3208  }
3209  else
3210  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3211  }
3212 
3213  /* update set of GC1 GUBs */
3214  gubconsGC1[*ngubconsGC1] = gubconsidx;
3215  (*ngubconsGC1)++;
3216 
3217  /* update maximum size of all GUB constraints */
3218  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3219  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3220 
3221  /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3222  if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3223  {
3224  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3225  ngubconsGOC1++;
3226  }
3227  else
3228  {
3229 #if GUBSPLITGNC1GUBS
3230  /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3231  if( !gubconswithF )
3232  {
3233  GUBVARSTATUS movevarstatus;
3234 
3235  assert(gubset->ngubconss < gubset->nvars);
3236 
3237  /* create a new GUB for GR part of splitting */
3238  SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3239  gubset->ngubconss++;
3240  ngubconss = gubset->ngubconss;
3241 
3242  /* fill GR with R variables in current GUB */
3243  for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3244  {
3245  movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3246  if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3247  {
3248  assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3249  SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3250  gubconsidx, ngubconss-1) );
3251  gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3252  movevarstatus;
3253  }
3254  }
3255 
3256  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3257  ngubconsGOC1++;
3258 
3259  gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3260  gubconsGR[*ngubconsGR] = ngubconss-1;
3261  (*ngubconsGR)++;
3262  }
3263  /* variables in C1, F, and maybe R: GNC1 GUB */
3264  else
3265  {
3266  assert(gubconswithF);
3267 
3268  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3269  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3270  (*ngubconsGFC1)++;
3271  }
3272 #else
3273  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3274  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3275  (*ngubconsGFC1)++;
3276 #endif
3277  }
3278  }
3279 
3280  /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3281  * are already sorted correctly
3282  */
3283  for( i = 0; i < nvarsC2; i++ )
3284  {
3285  var = varsC2[i];
3286  gubconsidx = gubset->gubconssidx[var];
3287  varidx = gubset->gubvarsidx[var];
3288 
3289  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3290  assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3291  assert(varidx == 0);
3292  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3293  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3294 
3295  /* set status of GC2 GUB */
3296  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3297 
3298  /* update group of GC2 GUBs */
3299  gubconsGC2[*ngubconsGC2] = gubconsidx;
3300  (*ngubconsGC2)++;
3301 
3302  /* update maximum size of all GUB constraints */
3303  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3304  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3305 
3306 #ifndef NDEBUG
3307  nvarsprocessed++;
3308 #endif
3309  }
3310 
3311  /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3312  * non-increasing number of variables in F, and
3313  * non-increasing max{x*_k : k in GFC1_j} in case of equality
3314  */
3315  for( i = 0; i < nvarsF; i++ )
3316  {
3317  var = varsF[i];
3318  gubconsidx = gubset->gubconssidx[var];
3319  varidx = gubset->gubvarsidx[var];
3320 
3321  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3322  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3323 
3324 #ifndef NDEBUG
3325  nvarsprocessed++;
3326 #endif
3327 
3328  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3329  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3330  {
3331  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3332  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3333  continue;
3334  }
3335 
3336  /* set status of GF GUB */
3337  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3338 
3339  /* update sorting key of corresponding GFC1 GUB */
3340  for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3341  {
3342  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3343  && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3344 
3345  /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3346  if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3347  {
3348  sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3349 
3350  if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3351  sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3352  }
3353  }
3354 
3355  /* update set of GFC1 GUBs */
3356  gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3357  (*ngubconsGFC1)++;
3358 
3359  /* update maximum size of all GUB constraints */
3360  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3361  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3362  }
3363 
3364  /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3365  * correctly
3366  */
3367  for( i = 0; i < nvarsR; i++ )
3368  {
3369  var = varsR[i];
3370  gubconsidx = gubset->gubconssidx[var];
3371  varidx = gubset->gubvarsidx[var];
3372 
3373  assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3374  assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3375 
3376 #ifndef NDEBUG
3377  nvarsprocessed++;
3378 #endif
3379 
3380  /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3381  if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3382  {
3383  assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3384  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3385  || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3386  continue;
3387  }
3388 
3389  /* set status of GR GUB */
3390  gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3391 
3392  /* update set of GR GUBs */
3393  gubconsGR[*ngubconsGR] = gubconsidx;
3394  (*ngubconsGR)++;
3395 
3396  /* update maximum size of all GUB constraints */
3397  if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3398  *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3399  }
3400  assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3401 
3402  /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3403  (*ngubconscapexceed) = ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3404  assert(*ngubconscapexceed >= 0);
3405 #ifndef NDEBUG
3406  {
3407  int check;
3408 
3409  check = 0;
3410 
3411  /* remaining not handled GUBs should only contain capacity exceeding variables */
3412  for( i = 0; i < ngubconss; i++ )
3413  {
3414  if( gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL )
3415  check++;
3416  }
3417  assert(check == *ngubconscapexceed);
3418  }
3419 #endif
3420 
3421  /* sort GFCI GUBs according to computed sorting keys */
3422  if( (*ngubconsGFC1) > 0 )
3423  {
3424  SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3425  }
3426 
3427  /* free temporary memory */
3428 #if GUBSPLITGNC1GUBS
3429  ngubconss = origngubconss;
3430 #endif
3431  SCIPfreeBufferArray(scip, &nC1varsingubcons);
3432  SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3433  SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3434 
3435  return SCIP_OKAY;
3436 }
3437 
3438 /** enlarges minweight table to at least the given length */
3439 static
3441  SCIP* scip, /**< SCIP data structure */
3442  SCIP_Longint** minweightsptr, /**< pointer to minweights table */
3443  int* minweightslen, /**< pointer to store number of entries in minweights table (incl. z=0) */
3444  int* minweightssize, /**< pointer to current size of minweights table */
3445  int newlen /**< new length of minweights table */
3446  )
3447 {
3448  int j;
3449 
3450  assert(minweightsptr != NULL);
3451  assert(*minweightsptr != NULL);
3452  assert(minweightslen != NULL);
3453  assert(*minweightslen >= 0);
3454  assert(minweightssize != NULL);
3455  assert(*minweightssize >= 0);
3456 
3457  if( newlen > *minweightssize )
3458  {
3459  int newsize;
3460 
3461  /* reallocate table memory */
3462  newsize = SCIPcalcMemGrowSize(scip, newlen);
3463  SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3464  *minweightssize = newsize;
3465  }
3466  assert(newlen <= *minweightssize);
3467 
3468  /* initialize new elements */
3469  for( j = *minweightslen; j < newlen; ++j )
3470  (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3471  *minweightslen = newlen;
3472 
3473  return SCIP_OKAY;
3474 }
3475 
3476 /** lifts given inequality
3477  * sum_{j in M_1} x_j <= alpha_0
3478  * valid for
3479  * 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 }
3480  * to a valid inequality
3481  * 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
3482  * <= alpha_0 + sum_{j in M_2} alpha_j
3483  * for
3484  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3485  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3486  * sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3487  * extended weight inequalities.
3488  */
3489 static
3491  SCIP* scip, /**< SCIP data structure */
3492  SCIP_VAR** vars, /**< variables in knapsack constraint */
3493  int nvars, /**< number of variables in knapsack constraint */
3494  int ntightened, /**< number of variables with tightened upper bound */
3495  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3496  SCIP_Longint capacity, /**< capacity of knapsack */
3497  SCIP_Real* solvals, /**< solution values of all problem variables */
3498  int* varsM1, /**< variables in M_1 */
3499  int* varsM2, /**< variables in M_2 */
3500  int* varsF, /**< variables in F */
3501  int* varsR, /**< variables in R */
3502  int nvarsM1, /**< number of variables in M_1 */
3503  int nvarsM2, /**< number of variables in M_2 */
3504  int nvarsF, /**< number of variables in F */
3505  int nvarsR, /**< number of variables in R */
3506  int alpha0, /**< rights hand side of given valid inequality */
3507  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3508  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3509  int* liftrhs /**< pointer to store right hand side of the lifted valid inequality */
3510  )
3511 {
3512  SCIP_Longint* minweights;
3513  SCIP_Real* sortkeys;
3514  SCIP_Longint fixedonesweight;
3515  int minweightssize;
3516  int minweightslen;
3517  int j;
3518  int w;
3519 
3520  assert(scip != NULL);
3521  assert(vars != NULL);
3522  assert(nvars >= 0);
3523  assert(weights != NULL);
3524  assert(capacity >= 0);
3525  assert(solvals != NULL);
3526  assert(varsM1 != NULL);
3527  assert(varsM2 != NULL);
3528  assert(varsF != NULL);
3529  assert(varsR != NULL);
3530  assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3531  assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3532  assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3533  assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3534  assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars - ntightened);
3535  assert(alpha0 >= 0);
3536  assert(liftcoefs != NULL);
3537  assert(cutact != NULL);
3538  assert(liftrhs != NULL);
3539 
3540  /* allocates temporary memory */
3541  minweightssize = nvarsM1 + 1;
3542  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3543  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3544 
3545  /* initializes data structures */
3546  BMSclearMemoryArray(liftcoefs, nvars);
3547  *cutact = 0.0;
3548 
3549  /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3550  * and calculates activity of the current valid inequality
3551  */
3552  for( j = 0; j < nvarsM1; j++ )
3553  {
3554  assert(liftcoefs[varsM1[j]] == 0);
3555  liftcoefs[varsM1[j]] = 1;
3556  sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3557  (*cutact) += solvals[varsM1[j]];
3558  }
3559 
3560  SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3561 
3562  /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3563  * min sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k} x_{j_k}
3564  * s.t. sum_{j in M_1} x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3565  * x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3566  * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3567  */
3568  minweights[0] = 0;
3569  for( w = 1; w <= nvarsM1; w++ )
3570  minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3571  minweightslen = nvarsM1 + 1;
3572 
3573  /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3574  fixedonesweight = 0;
3575  for( j = 0; j < nvarsM2; j++ )
3576  fixedonesweight += weights[varsM2[j]];
3577  assert(fixedonesweight >= 0);
3578 
3579  /* initializes right hand side of lifted valid inequality */
3580  *liftrhs = alpha0;
3581 
3582  /* sequentially up-lifts all variables in F: */
3583  for( j = 0; j < nvarsF; j++ )
3584  {
3585  SCIP_Longint weight;
3586  int liftvar;
3587  int liftcoef;
3588  int z;
3589 
3590  liftvar = varsF[j];
3591  weight = weights[liftvar];
3592  assert(liftvar >= 0 && liftvar < nvars);
3593  assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3594  assert(weight > 0);
3595 
3596  /* knapsack problem is infeasible:
3597  * sets z = 0
3598  */
3599  if( capacity - fixedonesweight - weight < 0 )
3600  {
3601  z = 0;
3602  }
3603  /* knapsack problem is feasible:
3604  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
3605  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3606  */
3607  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3608  {
3609  z = *liftrhs;
3610  }
3611  /* knapsack problem is feasible:
3612  * uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3613  */
3614  else
3615  {
3616  int left;
3617  int right;
3618  int middle;
3619 
3620  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3621  left = 0;
3622  right = (*liftrhs) + 1;
3623  while( left < right - 1 )
3624  {
3625  middle = (left + right) / 2;
3626  assert(0 <= middle && middle < minweightslen);
3627  if( minweights[middle] <= capacity - fixedonesweight - weight )
3628  left = middle;
3629  else
3630  right = middle;
3631  }
3632  assert(left == right - 1);
3633  assert(0 <= left && left < minweightslen);
3634  assert(minweights[left] <= capacity - fixedonesweight - weight );
3635  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3636 
3637  /* now z = left */
3638  z = left;
3639  assert(z <= *liftrhs);
3640  }
3641 
3642  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3643  liftcoef = (*liftrhs) - z;
3644  liftcoefs[liftvar] = liftcoef;
3645  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3646 
3647  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3648  if( liftcoef == 0 )
3649  continue;
3650 
3651  /* updates activity of current valid inequality */
3652  (*cutact) += liftcoef * solvals[liftvar];
3653 
3654  /* enlarges current minweight table:
3655  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3656  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3657  * and sets minweights_i[w] = infinity for
3658  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3659  */
3660  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3661 
3662  /* updates minweight table: minweight_i+1[w] =
3663  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3664  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3665  */
3666  for( w = minweightslen - 1; w >= 0; w-- )
3667  {
3668  SCIP_Longint min;
3669  if( w < liftcoef )
3670  {
3671  min = MIN(minweights[w], weight);
3672  minweights[w] = min;
3673  }
3674  else
3675  {
3676  assert(w >= liftcoef);
3677  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3678  minweights[w] = min;
3679  }
3680  }
3681  }
3682  assert(minweights[0] == 0);
3683 
3684  /* sequentially down-lifts all variables in M_2: */
3685  for( j = 0; j < nvarsM2; j++ )
3686  {
3687  SCIP_Longint weight;
3688  int liftvar;
3689  int liftcoef;
3690  int left;
3691  int right;
3692  int middle;
3693  int z;
3694 
3695  liftvar = varsM2[j];
3696  weight = weights[liftvar];
3697  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3698  assert(liftvar >= 0 && liftvar < nvars);
3699  assert(weight > 0);
3700 
3701  /* uses binary search to find
3702  * z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3703  */
3704  left = 0;
3705  right = minweightslen;
3706  while( left < right - 1 )
3707  {
3708  middle = (left + right) / 2;
3709  assert(0 <= middle && middle < minweightslen);
3710  if( minweights[middle] <= capacity - fixedonesweight + weight )
3711  left = middle;
3712  else
3713  right = middle;
3714  }
3715  assert(left == right - 1);
3716  assert(0 <= left && left < minweightslen);
3717  assert(minweights[left] <= capacity - fixedonesweight + weight );
3718  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3719 
3720  /* now z = left */
3721  z = left;
3722  assert(z >= *liftrhs);
3723 
3724  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3725  liftcoef = z - (*liftrhs);
3726  liftcoefs[liftvar] = liftcoef;
3727  assert(liftcoef >= 0);
3728 
3729  /* updates sum of weights of variables fixed to one */
3730  fixedonesweight -= weight;
3731 
3732  /* updates right-hand side of current valid inequality */
3733  (*liftrhs) += liftcoef;
3734  assert(*liftrhs >= alpha0);
3735 
3736  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3737  if( liftcoef == 0 )
3738  continue;
3739 
3740  /* updates activity of current valid inequality */
3741  (*cutact) += liftcoef * solvals[liftvar];
3742 
3743  /* enlarges current minweight table:
3744  * from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3745  * to |M1| + sum_{k=1}^{i } alpha_{j_k} + 1 entries
3746  * and sets minweights_i[w] = infinity for
3747  * w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3748  */
3749  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3750 
3751  /* updates minweight table: minweight_i+1[w] =
3752  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
3753  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3754  */
3755  for( w = minweightslen - 1; w >= 0; w-- )
3756  {
3757  SCIP_Longint min;
3758  if( w < liftcoef )
3759  {
3760  min = MIN(minweights[w], weight);
3761  minweights[w] = min;
3762  }
3763  else
3764  {
3765  assert(w >= liftcoef);
3766  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3767  minweights[w] = min;
3768  }
3769  }
3770  }
3771  assert(fixedonesweight == 0);
3772  assert(*liftrhs >= alpha0);
3773 
3774  /* sequentially up-lifts all variables in R: */
3775  for( j = 0; j < nvarsR; j++ )
3776  {
3777  SCIP_Longint weight;
3778  int liftvar;
3779  int liftcoef;
3780  int z;
3781 
3782  liftvar = varsR[j];
3783  weight = weights[liftvar];
3784  assert(liftvar >= 0 && liftvar < nvars);
3785  assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3786  assert(weight > 0);
3787  assert(capacity - weight >= 0);
3788  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3789 
3790  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3791  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3792  */
3793  if( minweights[*liftrhs] <= capacity - weight )
3794  {
3795  z = *liftrhs;
3796  }
3797  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3798  */
3799  else
3800  {
3801  int left;
3802  int right;
3803  int middle;
3804 
3805  left = 0;
3806  right = (*liftrhs) + 1;
3807  while( left < right - 1)
3808  {
3809  middle = (left + right) / 2;
3810  assert(0 <= middle && middle < minweightslen);
3811  if( minweights[middle] <= capacity - weight )
3812  left = middle;
3813  else
3814  right = middle;
3815  }
3816  assert(left == right - 1);
3817  assert(0 <= left && left < minweightslen);
3818  assert(minweights[left] <= capacity - weight );
3819  assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3820 
3821  /* now z = left */
3822  z = left;
3823  assert(z <= *liftrhs);
3824  }
3825 
3826  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3827  liftcoef = (*liftrhs) - z;
3828  liftcoefs[liftvar] = liftcoef;
3829  assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3830 
3831  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3832  if( liftcoef == 0 )
3833  continue;
3834 
3835  /* updates activity of current valid inequality */
3836  (*cutact) += liftcoef * solvals[liftvar];
3837 
3838  /* updates minweight table: minweight_i+1[w] =
3839  * min{ minweight_i[w], a_{j_i}}, if w < alpha_j_i
3840  * min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
3841  */
3842  for( w = *liftrhs; w >= 0; w-- )
3843  {
3844  SCIP_Longint min;
3845  if( w < liftcoef )
3846  {
3847  min = MIN(minweights[w], weight);
3848  minweights[w] = min;
3849  }
3850  else
3851  {
3852  assert(w >= liftcoef);
3853  min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3854  minweights[w] = min;
3855  }
3856  }
3857  }
3858 
3859  /* frees temporary memory */
3860  SCIPfreeBufferArray(scip, &sortkeys);
3861  SCIPfreeBufferArray(scip, &minweights);
3862 
3863  return SCIP_OKAY;
3864 }
3865 
3866 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3867 static
3869  SCIP_Longint val1, /**< first value to add */
3870  SCIP_Longint val2 /**< second value to add */
3871  )
3872 {
3873  assert(val1 >= 0);
3874  assert(val2 >= 0);
3875 
3876  if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3877  return SCIP_LONGINT_MAX;
3878  else
3879  {
3880  assert(val1 <= SCIP_LONGINT_MAX - val2);
3881  return (val1 + val2);
3882  }
3883 }
3884 
3885 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3886 static
3888  SCIP_Longint* minweights, /**< minweight table to compute */
3889  SCIP_Longint* finished, /**< given finished table */
3890  SCIP_Longint* unfinished, /**< given unfinished table */
3891  int minweightslen /**< length of minweight, finished, and unfinished tables */
3892  )
3893 {
3894  int w1;
3895  int w2;
3896 
3897  /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3898  * note that finished and unfished arrays sorted by non-decreasing weight
3899  */
3900 
3901  /* initialize minweight with w2 = 0 */
3902  w2 = 0;
3903  assert(unfinished[w2] == 0);
3904  for( w1 = 0; w1 < minweightslen; w1++ )
3905  minweights[w1] = finished[w1];
3906 
3907  /* consider w2 = 1, ..., minweightslen-1 */
3908  for( w2 = 1; w2 < minweightslen; w2++ )
3909  {
3910  if( unfinished[w2] >= SCIP_LONGINT_MAX )
3911  break;
3912 
3913  for( w1 = 0; w1 < minweightslen - w2; w1++ )
3914  {
3915  SCIP_Longint temp;
3916 
3917  temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3918  if( temp <= minweights[w1+w2] )
3919  minweights[w1+w2] = temp;
3920  }
3921  }
3922 }
3923 
3924 /** lifts given inequality
3925  * sum_{j in C_1} x_j <= alpha_0
3926  * valid for
3927  * 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;
3928  * sum_{j in Q_i} x_j <= 1, forall i in I }
3929  * to a valid inequality
3930  * 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
3931  * <= alpha_0 + sum_{j in C_2} alpha_j
3932  * for
3933  * 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 };
3934  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
3935  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3936  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
3937  */
3938 static
3940  SCIP* scip, /**< SCIP data structure */
3941  SCIP_GUBSET* gubset, /**< GUB set data structure */
3942  SCIP_VAR** vars, /**< variables in knapsack constraint */
3943  int ngubconscapexceed, /**< number of GUBs with only capacity exceeding variables */
3944  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
3945  SCIP_Longint capacity, /**< capacity of knapsack */
3946  SCIP_Real* solvals, /**< solution values of all knapsack variables */
3947  int* gubconsGC1, /**< GUBs in GC1(GNC1+GOC1) */
3948  int* gubconsGC2, /**< GUBs in GC2 */
3949  int* gubconsGFC1, /**< GUBs in GFC1(GNC1+GF) */
3950  int* gubconsGR, /**< GUBs in GR */
3951  int ngubconsGC1, /**< number of GUBs in GC1(GNC1+GOC1) */
3952  int ngubconsGC2, /**< number of GUBs in GC2 */
3953  int ngubconsGFC1, /**< number of GUBs in GFC1(GNC1+GF) */
3954  int ngubconsGR, /**< number of GUBs in GR */
3955  int alpha0, /**< rights hand side of given valid inequality */
3956  int* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
3957  SCIP_Real* cutact, /**< pointer to store activity of lifted valid inequality */
3958  int* liftrhs, /**< pointer to store right hand side of the lifted valid inequality */
3959  int maxgubvarssize /**< maximal size of GUB constraints */
3960  )
3961 {
3962  SCIP_Longint* minweights;
3963  SCIP_Longint* finished;
3964  SCIP_Longint* unfinished;
3965  int* gubconsGOC1;
3966  int* gubconsGNC1;
3967  int* liftgubvars;
3968  SCIP_Longint fixedonesweight;
3969  SCIP_Longint weight;
3970  SCIP_Longint weightdiff1;
3971  SCIP_Longint weightdiff2;
3972  SCIP_Longint min;
3973  int minweightssize;
3974  int minweightslen;
3975  int nvars;
3976  int varidx;
3977  int liftgubconsidx;
3978  int liftvar;
3979  int sumliftcoef;
3980  int liftcoef;
3981  int ngubconsGOC1;
3982  int ngubconsGNC1;
3983  int left;
3984  int right;
3985  int middle;
3986  int nliftgubvars;
3987  int tmplen;
3988  int tmpsize;
3989  int j;
3990  int k;
3991  int w;
3992  int z;
3993 #ifndef NDEBUG
3994  int ngubconss;
3995  int nliftgubC1;
3996 
3997  assert(gubset != NULL);
3998  ngubconss = gubset->ngubconss;
3999 #else
4000  assert(gubset != NULL);
4001 #endif
4002 
4003  nvars = gubset->nvars;
4004 
4005  assert(scip != NULL);
4006  assert(vars != NULL);
4007  assert(nvars >= 0);
4008  assert(weights != NULL);
4009  assert(capacity >= 0);
4010  assert(solvals != NULL);
4011  assert(gubconsGC1 != NULL);
4012  assert(gubconsGC2 != NULL);
4013  assert(gubconsGFC1 != NULL);
4014  assert(gubconsGR != NULL);
4015  assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
4016  assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
4017  assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
4018  assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
4019  assert(alpha0 >= 0);
4020  assert(liftcoefs != NULL);
4021  assert(cutact != NULL);
4022  assert(liftrhs != NULL);
4023 
4024  minweightssize = ngubconsGC1+1;
4025 
4026  /* allocates temporary memory */
4027  SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
4028  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
4029  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
4030  SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
4031  SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
4032  SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
4033 
4034  /* initializes data structures */
4035  BMSclearMemoryArray(liftcoefs, nvars);
4036  *cutact = 0.0;
4037 
4038  /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
4039  * valid inequality
4040  */
4041  ngubconsGOC1 = 0;
4042  ngubconsGNC1 = 0;
4043  for( j = 0; j < ngubconsGC1; j++ )
4044  {
4045  if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
4046  {
4047  gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
4048  ngubconsGOC1++;
4049  }
4050  else
4051  {
4052  assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4053  gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
4054  ngubconsGNC1++;
4055  }
4056  for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
4057  && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4058  {
4059  varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
4060  assert(varidx >= 0 && varidx < nvars);
4061  assert(liftcoefs[varidx] == 0);
4062 
4063  liftcoefs[varidx] = 1;
4064  (*cutact) += solvals[varidx];
4065  }
4066  assert(k >= 1);
4067  }
4068  assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4069  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4070 
4071  /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4072  * - finished_i[w] =
4073  * min sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4074  * s.t. sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j >= w
4075  * sum_{j in Q_k} x_j <= 1
4076  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4077  * - unfinished_i[w] =
4078  * min sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4079  * s.t. sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j >= w
4080  * sum_{j in Q_k} x_j <= 1
4081  * x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4082  * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4083  */
4084 
4085  /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4086  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4087  * 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
4088  * comes from the first variable in the GUB
4089  */
4090  assert(ngubconsGOC1 <= ngubconsGC1);
4091  finished[0] = 0;
4092  for( w = 1; w <= ngubconsGOC1; w++ )
4093  {
4094  liftgubconsidx = gubconsGOC1[w-1];
4095 
4096  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4097  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4098 
4099  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4100 
4101  assert(varidx >= 0 && varidx < nvars);
4102  assert(liftcoefs[varidx] == 1);
4103 
4104  min = weights[varidx];
4105  finished[w] = finished[w-1] + min;
4106 
4107 #ifndef NDEBUG
4108  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4109  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4110  {
4111  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4112  assert(varidx >= 0 && varidx < nvars);
4113  assert(liftcoefs[varidx] == 1);
4114  assert(weights[varidx] >= min);
4115  }
4116 #endif
4117  }
4118  for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4119  finished[w] = SCIP_LONGINT_MAX;
4120 
4121  /* initialize unfinished table; note that variables in GNC1 GUBs
4122  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4123  * 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
4124  * comes from the first variable in the GUB
4125  */
4126  assert(ngubconsGNC1 <= ngubconsGC1);
4127  unfinished[0] = 0;
4128  for( w = 1; w <= ngubconsGNC1; w++ )
4129  {
4130  liftgubconsidx = gubconsGNC1[w-1];
4131 
4132  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4133  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4134 
4135  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4136 
4137  assert(varidx >= 0 && varidx < nvars);
4138  assert(liftcoefs[varidx] == 1);
4139 
4140  min = weights[varidx];
4141  unfinished[w] = unfinished[w-1] + min;
4142 
4143 #ifndef NDEBUG
4144  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4145  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4146  {
4147  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4148  assert(varidx >= 0 && varidx < nvars);
4149  assert(liftcoefs[varidx] == 1);
4150  assert(weights[varidx] >= min );
4151  }
4152 #endif
4153  }
4154  for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4155  unfinished[w] = SCIP_LONGINT_MAX;
4156 
4157  /* initialize minweights table; note that variables in GC1 GUBs
4158  * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4159  * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4160  * consuming) because is it has to be build using weights from C1 only.
4161  */
4162  assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4163  minweights[0] = 0;
4164  for( w = 1; w <= ngubconsGC1; w++ )
4165  {
4166  liftgubconsidx = gubconsGC1[w-1];
4167 
4168  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4169  || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4170  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4171 
4172  varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4173 
4174  assert(varidx >= 0 && varidx < nvars);
4175  assert(liftcoefs[varidx] == 1);
4176 
4177  min = weights[varidx];
4178  minweights[w] = minweights[w-1] + min;
4179 
4180 #ifndef NDEBUG
4181  for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4182  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4183  {
4184  varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4185  assert(varidx >= 0 && varidx < nvars);
4186  assert(liftcoefs[varidx] == 1);
4187  assert(weights[varidx] >= min);
4188  }
4189 #endif
4190  }
4191  minweightslen = ngubconsGC1 + 1;
4192 
4193  /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4194  fixedonesweight = 0;
4195  for( j = 0; j < ngubconsGC2; j++ )
4196  {
4197  varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4198 
4199  assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4200  assert(varidx >= 0 && varidx < nvars);
4201  assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4202 
4203  fixedonesweight += weights[varidx];
4204  }
4205  assert(fixedonesweight >= 0);
4206 
4207  /* initializes right hand side of lifted valid inequality */
4208  *liftrhs = alpha0;
4209 
4210  /* sequentially up-lifts all variables in GFC1 GUBs */
4211  for( j = 0; j < ngubconsGFC1; j++ )
4212  {
4213  liftgubconsidx = gubconsGFC1[j];
4214  assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4215 
4216  /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4217  * compute minweight table via updated unfinished table and aleady upto date finished table;
4218  */
4219  k = 0;
4220  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4221  {
4222  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4223  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4224  assert(ngubconsGNC1 > 0);
4225 
4226  /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4227  * are considered for the lifting, i.e., not capacity exceeding
4228  */
4229  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4230  && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4231  liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4232  assert(k >= 1);
4233 
4234  /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4235  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4236  */
4237  weight = weights[liftgubvars[0]];
4238 
4239  weightdiff2 = unfinished[ngubconsGNC1] - weight;
4240  unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4241  for( w = ngubconsGNC1-1; w >= 1; w-- )
4242  {
4243  weightdiff1 = weightdiff2;
4244  weightdiff2 = unfinished[w] - weight;
4245 
4246  if( unfinished[w] < weightdiff1 )
4247  unfinished[w] = weightdiff1;
4248  else
4249  break;
4250  }
4251  ngubconsGNC1--;
4252 
4253  /* computes minweights table by combining unfished and fished tables */
4254  computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4255  assert(minweights[0] == 0);
4256  }
4257  /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4258  * are therefore not in the unfinished table
4259  */
4260  else
4261  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4262 
4263 #ifndef NDEBUG
4264  nliftgubC1 = k;
4265 #endif
4266  nliftgubvars = k;
4267  sumliftcoef = 0;
4268 
4269  /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4270  for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4271  {
4272  if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4273  || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4274  {
4275  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4276  weight = weights[liftvar];
4277  assert(weight > 0);
4278  assert(liftvar >= 0 && liftvar < nvars);
4279  assert(capacity - weight >= 0);
4280 
4281  /* put variable into array of variables in GUB that are considered for the lifting,
4282  * i.e., not capacity exceeding
4283  */
4284  liftgubvars[nliftgubvars] = liftvar;
4285  nliftgubvars++;
4286 
4287  /* knapsack problem is infeasible:
4288  * sets z = 0
4289  */
4290  if( capacity - fixedonesweight - weight < 0 )
4291  {
4292  z = 0;
4293  }
4294  /* knapsack problem is feasible:
4295  * sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} } = liftrhs,
4296  * if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4297  */
4298  else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4299  {
4300  z = *liftrhs;
4301  }
4302  /* knapsack problem is feasible:
4303  * binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4304  */
4305  else
4306  {
4307  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4308  left = 0;
4309  right = (*liftrhs) + 1;
4310  while( left < right - 1 )
4311  {
4312  middle = (left + right) / 2;
4313  assert(0 <= middle && middle < minweightslen);
4314  if( minweights[middle] <= capacity - fixedonesweight - weight )
4315  left = middle;
4316  else
4317  right = middle;
4318  }
4319  assert(left == right - 1);
4320  assert(0 <= left && left < minweightslen);
4321  assert(minweights[left] <= capacity - fixedonesweight - weight);
4322  assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4323 
4324  /* now z = left */
4325  z = left;
4326  assert(z <= *liftrhs);
4327  }
4328 
4329  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4330  liftcoef = (*liftrhs) - z;
4331  liftcoefs[liftvar] = liftcoef;
4332  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4333 
4334  /* updates activity of current valid inequality */
4335  (*cutact) += liftcoef * solvals[liftvar];
4336 
4337  /* updates sum of all lifting coefficients in GUB */
4338  sumliftcoef += liftcoefs[liftvar];
4339  }
4340  else
4341  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4342  }
4343  /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4344  assert(nliftgubvars > nliftgubC1);
4345 
4346  /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4347  * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4348  * not needed for GF GUBs
4349  */
4350  if( sumliftcoef == 0 )
4351  {
4352  if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4353  {
4354  weight = weights[liftgubvars[0]];
4355  /* update finished table and minweights table by applying special case of
4356  * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4357  * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4358  */
4359  for( w = minweightslen-1; w >= 1; w-- )
4360  {
4361  SCIP_Longint tmpval;
4362 
4363  tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4364  finished[w] = MIN(finished[w], tmpval);
4365 
4366  tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4367  minweights[w] = MIN(minweights[w], tmpval);
4368  }
4369  }
4370  else
4371  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4372 
4373  continue;
4374  }
4375 
4376  /* enlarges current minweights tables(finished, unfinished, minweights):
4377  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4378  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4379  * and sets minweights_i[w] = infinity for
4380  * 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
4381  */
4382  tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4383  tmpsize = minweightssize;
4384  SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4385  tmplen = minweightslen;
4386  tmpsize = minweightssize;
4387  SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4388  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4389 
4390  /* update finished table and minweight table;
4391  * note that instead of computing minweight table from updated finished and updated unfinished table again
4392  * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4393  * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4394  * not needed because only finished table changed at this point and the change was "adding" one weight)
4395  *
4396  * update formular for minweight table is: minweight_i+1[w] =
4397  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4398  * formular for finished table has the same pattern.
4399  */
4400  for( w = minweightslen-1; w >= 0; w-- )
4401  {
4402  SCIP_Longint minminweight;
4403  SCIP_Longint minfinished;
4404 
4405  for( k = 0; k < nliftgubvars; k++ )
4406  {
4407  liftcoef = liftcoefs[liftgubvars[k]];
4408  weight = weights[liftgubvars[k]];
4409 
4410  if( w < liftcoef )
4411  {
4412  minfinished = MIN(finished[w], weight);
4413  minminweight = MIN(minweights[w], weight);
4414 
4415  finished[w] = minfinished;
4416  minweights[w] = minminweight;
4417  }
4418  else
4419  {
4420  SCIP_Longint tmpval;
4421 
4422  assert(w >= liftcoef);
4423 
4424  tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4425  minfinished = MIN(finished[w], tmpval);
4426 
4427  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4428  minminweight = MIN(minweights[w], tmpval);
4429 
4430  finished[w] = minfinished;
4431  minweights[w] = minminweight;
4432  }
4433  }
4434  }
4435  assert(minweights[0] == 0);
4436  }
4437  assert(ngubconsGNC1 == 0);
4438 
4439  /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4440  * therefore, only work with minweight table from here on
4441  */
4442 
4443  /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4444  for( j = 0; j < ngubconsGC2; j++ )
4445  {
4446  liftgubconsidx = gubconsGC2[j];
4447 
4448  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4449  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4450  assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4451  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4452 
4453  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4454  weight = weights[liftvar];
4455 
4456  assert(liftvar >= 0 && liftvar < nvars);
4457  assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4458  assert(weight > 0);
4459 
4460  /* uses binary search to find
4461  * z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4462  */
4463  left = 0;
4464  right = minweightslen;
4465  while( left < right - 1 )
4466  {
4467  middle = (left + right) / 2;
4468  assert(0 <= middle && middle < minweightslen);
4469  if( minweights[middle] <= capacity - fixedonesweight + weight )
4470  left = middle;
4471  else
4472  right = middle;
4473  }
4474  assert(left == right - 1);
4475  assert(0 <= left && left < minweightslen);
4476  assert(minweights[left] <= capacity - fixedonesweight + weight);
4477  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4478 
4479  /* now z = left */
4480  z = left;
4481  assert(z >= *liftrhs);
4482 
4483  /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4484  liftcoef = z - (*liftrhs);
4485  liftcoefs[liftvar] = liftcoef;
4486  assert(liftcoef >= 0);
4487 
4488  /* updates sum of weights of variables fixed to one */
4489  fixedonesweight -= weight;
4490 
4491  /* updates right-hand side of current valid inequality */
4492  (*liftrhs) += liftcoef;
4493  assert(*liftrhs >= alpha0);
4494 
4495  /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4496  if( liftcoef == 0 )
4497  continue;
4498 
4499  /* updates activity of current valid inequality */
4500  (*cutact) += liftcoef * solvals[liftvar];
4501 
4502  /* enlarges current minweight table:
4503  * from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4504  * to |gubconsGC1| + sum_{k=1,2,...,i }sum_{j in Q_k} alpha_j + 1 entries
4505  * and sets minweights_i[w] = infinity for
4506  * 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
4507  */
4508  SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4509 
4510  /* updates minweight table: minweight_i+1[w] =
4511  * min{ minweights_i[w], a_{j_i}}, if w < alpha_j_i
4512  * min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i}, if w >= alpha_j_i
4513  */
4514  for( w = minweightslen - 1; w >= 0; w-- )
4515  {
4516  if( w < liftcoef )
4517  {
4518  min = MIN(minweights[w], weight);
4519  minweights[w] = min;
4520  }
4521  else
4522  {
4523  SCIP_Longint tmpval;
4524 
4525  assert(w >= liftcoef);
4526 
4527  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4528  min = MIN(minweights[w], tmpval);
4529  minweights[w] = min;
4530  }
4531  }
4532  }
4533  assert(fixedonesweight == 0);
4534  assert(*liftrhs >= alpha0);
4535 
4536  /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4537  for( j = 0; j < ngubconsGR; j++ )
4538  {
4539  liftgubconsidx = gubconsGR[j];
4540 
4541  assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4542  assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4543 
4544  sumliftcoef = 0;
4545  nliftgubvars = 0;
4546  for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4547  {
4548  if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4549  {
4550  liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4551  weight = weights[liftvar];
4552  assert(weight > 0);
4553  assert(liftvar >= 0 && liftvar < nvars);
4554  assert(capacity - weight >= 0);
4555  assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4556 
4557  /* put variable into array of variables in GUB that are considered for the lifting,
4558  * i.e., not capacity exceeding
4559  */
4560  liftgubvars[nliftgubvars] = liftvar;
4561  nliftgubvars++;
4562 
4563  /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4564  * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4565  */
4566  if( minweights[*liftrhs] <= capacity - weight )
4567  {
4568  z = *liftrhs;
4569  }
4570  /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4571  */
4572  else
4573  {
4574  left = 0;
4575  right = (*liftrhs) + 1;
4576  while( left < right - 1 )
4577  {
4578  middle = (left + right) / 2;
4579  assert(0 <= middle && middle < minweightslen);
4580  if( minweights[middle] <= capacity - weight )
4581  left = middle;
4582  else
4583  right = middle;
4584  }
4585  assert(left == right - 1);
4586  assert(0 <= left && left < minweightslen);
4587  assert(minweights[left] <= capacity - weight);
4588  assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4589 
4590  /* now z = left */
4591  z = left;
4592  assert(z <= *liftrhs);
4593  }
4594  /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4595  liftcoef = (*liftrhs) - z;
4596  liftcoefs[liftvar] = liftcoef;
4597  assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4598 
4599  /* updates activity of current valid inequality */
4600  (*cutact) += liftcoef * solvals[liftvar];
4601 
4602  /* updates sum of all lifting coefficients in GUB */
4603  sumliftcoef += liftcoefs[liftvar];
4604  }
4605  else
4606  assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4607  }
4608  assert(nliftgubvars >= 1); /* at least one variable is in R */
4609 
4610  /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4611  if( sumliftcoef == 0 )
4612  continue;
4613 
4614  /* updates minweight table: minweight_i+1[w] =
4615  * min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4616  */
4617  for( w = *liftrhs; w >= 0; w-- )
4618  {
4619  for( k = 0; k < nliftgubvars; k++ )
4620  {
4621  liftcoef = liftcoefs[liftgubvars[k]];
4622  weight = weights[liftgubvars[k]];
4623 
4624  if( w < liftcoef )
4625  {
4626  min = MIN(minweights[w], weight);
4627  minweights[w] = min;
4628  }
4629  else
4630  {
4631  SCIP_Longint tmpval;
4632 
4633  assert(w >= liftcoef);
4634 
4635  tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4636  min = MIN(minweights[w], tmpval);
4637  minweights[w] = min;
4638  }
4639  }
4640  }
4641  assert(minweights[0] == 0);
4642  }
4643 
4644  /* frees temporary memory */
4645  SCIPfreeBufferArray(scip, &minweights);
4646  SCIPfreeBufferArray(scip, &finished);
4647  SCIPfreeBufferArray(scip, &unfinished);
4648  SCIPfreeBufferArray(scip, &liftgubvars);
4649  SCIPfreeBufferArray(scip, &gubconsGOC1 );
4650  SCIPfreeBufferArray(scip, &gubconsGNC1);
4651 
4652  return SCIP_OKAY;
4653 }
4654 
4655 /** lifts given minimal cover inequality
4656  * \f[
4657  * \sum_{j \in C} x_j \leq |C| - 1
4658  * \f]
4659  * valid for
4660  * \f[
4661  * S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4662  * \f]
4663  * to a valid inequality
4664  * \f[
4665  * \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4666  * \f]
4667  * for
4668  * \f[
4669  * S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4670  * \f]
4671  * uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4672  */
4673 static
4675  SCIP* scip, /**< SCIP data structure */
4676  SCIP_VAR** vars, /**< variables in knapsack constraint */
4677  int nvars, /**< number of variables in knapsack constraint */
4678  int ntightened, /**< number of variables with tightened upper bound */
4679  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4680  SCIP_Longint capacity, /**< capacity of knapsack */
4681  SCIP_Real* solvals, /**< solution values of all problem variables */
4682  int* covervars, /**< cover variables */
4683  int* noncovervars, /**< noncover variables */
4684  int ncovervars, /**< number of cover variables */
4685  int nnoncovervars, /**< number of noncover variables */
4686  SCIP_Longint coverweight, /**< weight of cover */
4687  SCIP_Real* liftcoefs, /**< pointer to store lifting coefficient of vars in knapsack constraint */
4688  SCIP_Real* cutact /**< pointer to store activity of lifted valid inequality */
4689  )
4690 {
4691  SCIP_Longint* maxweightsums;
4692  SCIP_Longint* intervalends;
4693  SCIP_Longint* rhos;
4694  SCIP_Real* sortkeys;
4695  SCIP_Longint lambda;
4696  int j;
4697  int h;
4698 
4699  assert(scip != NULL);
4700  assert(vars != NULL);
4701  assert(nvars >= 0);
4702  assert(weights != NULL);
4703  assert(capacity >= 0);
4704  assert(solvals != NULL);
4705  assert(covervars != NULL);
4706  assert(noncovervars != NULL);
4707  assert(ncovervars > 0 && ncovervars <= nvars);
4708  assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4709  assert(ncovervars + nnoncovervars == nvars - ntightened);
4710  assert(liftcoefs != NULL);
4711  assert(cutact != NULL);
4712 
4713  /* allocates temporary memory */
4714  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4715  SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4716  SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4717  SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4718 
4719  /* initializes data structures */
4720  BMSclearMemoryArray(liftcoefs, nvars);
4721  *cutact = 0.0;
4722 
4723  /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4724  * and calculates activity of current valid inequality
4725  */
4726  for( j = 0; j < ncovervars; j++ )
4727  {
4728  assert(liftcoefs[covervars[j]] == 0.0);
4729  liftcoefs[covervars[j]] = 1.0;
4730  sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4731  (*cutact) += solvals[covervars[j]];
4732  }
4733  SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4734 
4735  /* calculates weight excess of cover C */
4736  lambda = coverweight - capacity;
4737  assert(lambda > 0);
4738 
4739  /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4740  maxweightsums[0] = 0;
4741  for( h = 1; h <= ncovervars; h++ )
4742  {
4743  maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4744  intervalends[h-1] = maxweightsums[h] - lambda;
4745  rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4746  }
4747 
4748  /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4749  for( j = 0; j < nnoncovervars; j++ )
4750  sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4751  SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4752 
4753  /* calculates lifting coefficient for all variables in N\C */
4754  h = 0;
4755  for( j = 0; j < nnoncovervars; j++ )
4756  {
4757  int liftvar;
4758  SCIP_Longint weight;
4759  SCIP_Real liftcoef;
4760 
4761  liftvar = noncovervars[j];
4762  weight = weights[liftvar];
4763 
4764  while( intervalends[h] < weight )
4765  h++;
4766 
4767  if( h == 0 )
4768  liftcoef = h;
4769  else
4770  {
4771  if( weight <= intervalends[h-1] + rhos[h] )
4772  {
4773  SCIP_Real tmp1;
4774  SCIP_Real tmp2;
4775  tmp1 = (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4776  tmp2 = (SCIP_Real) rhos[1];
4777  liftcoef = h - ( tmp1 / tmp2 );
4778  }
4779  else
4780  liftcoef = h;
4781  }
4782 
4783  /* sets lifting coefficient */
4784  assert(liftcoefs[liftvar] == 0.0);
4785  liftcoefs[liftvar] = liftcoef;
4786 
4787  /* updates activity of current valid inequality */
4788  (*cutact) += liftcoef * solvals[liftvar];
4789  }
4790 
4791  /* frees temporary memory */
4792  SCIPfreeBufferArray(scip, &rhos);
4793  SCIPfreeBufferArray(scip, &intervalends);
4794  SCIPfreeBufferArray(scip, &maxweightsums);
4795  SCIPfreeBufferArray(scip, &sortkeys);
4796 
4797  return SCIP_OKAY;
4798 }
4799 
4800 
4801 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4802  * given knapsack problem
4803 */
4804 static
4806  SCIP* scip, /**< SCIP data structure */
4807  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
4808  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
4809  SCIP_VAR** vars, /**< variables in knapsack constraint */
4810  int nvars, /**< number of variables in knapsack constraint */
4811  int ntightened, /**< number of variables with tightened upper bound */
4812  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
4813  SCIP_Longint capacity, /**< capacity of knapsack */
4814  SCIP_Real* solvals, /**< solution values of all problem variables */
4815  int* mincovervars, /**< mincover variables */
4816  int* nonmincovervars, /**< nonmincover variables */
4817  int nmincovervars, /**< number of mincover variables */
4818  int nnonmincovervars, /**< number of nonmincover variables */
4819  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
4820  SCIP_GUBSET* gubset, /**< GUB set data structure, NULL if no GUB information should be used */
4821  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
4822  int* ncuts /**< pointer to add up the number of found cuts */
4823  )
4824 {
4825  int* varsC1;
4826  int* varsC2;
4827  int* varsF;
4828  int* varsR;
4829  int nvarsC1;
4830  int nvarsC2;
4831  int nvarsF;
4832  int nvarsR;
4833  SCIP_Real cutact;
4834  int* liftcoefs;
4835  int liftrhs;
4836 
4837  assert( cutoff != NULL );
4838  *cutoff = FALSE;
4839 
4840  /* allocates temporary memory */
4841  SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4842  SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4843  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4844  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4845  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4846 
4847  /* 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
4848  * as follows
4849  * C_2 = { j in C : x*_j = 1 } and
4850  * C_1 = C\C_2
4851  */
4852  getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4853  assert(nvarsC1 + nvarsC2 == nmincovervars);
4854  assert(nmincovervars > 0);
4855  assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4856 
4857  /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4858  if( nvarsC1 < 2 && nvarsC2 > 0)
4859  {
4860  SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4861  assert(nvarsC1 >= 1);
4862  }
4863  assert(nvarsC2 == 0 || nvarsC1 >= 1);
4864 
4865  /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4866  * R = { j in N\C : x*_j = 0 } and
4867  * F = (N\C)\F
4868  */
4869  getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4870  assert(nvarsF + nvarsR == nnonmincovervars);
4871  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4872 
4873  /* lift cuts without GUB information */
4874  if( gubset == NULL )
4875  {
4876  /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4877  * lifting procedure
4878  */
4879  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4880 
4881  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4882  *
4883  * 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 }
4884  *
4885  * 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
4886  *
4887  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
4888  *
4889  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4890  * up-lifting for the variables in R according to the second level lifting sequence
4891  */
4892  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4893  varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4894  }
4895  /* lift cuts with GUB information */
4896  else
4897  {
4898  int* gubconsGC1;
4899  int* gubconsGC2;
4900  int* gubconsGFC1;
4901  int* gubconsGR;
4902  int ngubconsGC1;
4903  int ngubconsGC2;
4904  int ngubconsGFC1;
4905  int ngubconsGR;
4906  int ngubconss;
4907  int nconstightened;
4908  int maxgubvarssize;
4909 
4910  assert(nvars == gubset->nvars);
4911 
4912  ngubconsGC1 = 0;
4913  ngubconsGC2 = 0;
4914  ngubconsGFC1 = 0;
4915  ngubconsGR = 0;
4916  ngubconss = gubset->ngubconss;
4917  nconstightened = 0;
4918  maxgubvarssize = 0;
4919 
4920  /* allocates temporary memory */
4921  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4922  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4923  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4924  SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4925 
4926  /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4927  * the GUBs for the sequential GUB wise lifting procedure
4928  */
4929  SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4930  nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4931  &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4932 
4933  /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4934  *
4935  * 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,
4936  * sum_{j in Q_i} x_j <= 1, forall i in I }
4937  *
4938  * 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
4939  *
4940  * 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 },
4941  *
4942  * uses sequential up-lifting for the variables in GUB constraints in gubconsGFC1,
4943  * sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4944  * sequential up-lifting for the variabels in GUB constraints in gubconsGR.
4945  */
4946  SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4947  gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4948  MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4949 
4950  /* frees temporary memory */
4951  SCIPfreeBufferArray(scip, &gubconsGR);
4952  SCIPfreeBufferArray(scip, &gubconsGFC1);
4953  SCIPfreeBufferArray(scip, &gubconsGC2);
4954  SCIPfreeBufferArray(scip, &gubconsGC1);
4955  }
4956 
4957  /* checks, if lifting yielded a violated cut */
4958  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4959  {
4960  SCIP_ROW* row;
4961  char name[SCIP_MAXSTRLEN];
4962  int j;
4963 
4964  /* creates LP row */
4965  assert( cons == NULL || sepa == NULL );
4966  if ( cons != NULL )
4967  {
4969  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4970  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4971  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4972  }
4973  else if ( sepa != NULL )
4974  {
4975  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4976  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4977  }
4978  else
4979  {
4980  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4981  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4982  }
4983 
4984  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4985  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4986  assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4987  for( j = 0; j < nvarsC1; j++ )
4988  {
4989  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4990  }
4991  for( j = 0; j < nvarsC2; j++ )
4992  {
4993  if( liftcoefs[varsC2[j]] > 0 )
4994  {
4995  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4996  }
4997  }
4998  for( j = 0; j < nvarsF; j++ )
4999  {
5000  if( liftcoefs[varsF[j]] > 0 )
5001  {
5002  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5003  }
5004  }
5005  for( j = 0; j < nvarsR; j++ )
5006  {
5007  if( liftcoefs[varsR[j]] > 0 )
5008  {
5009  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5010  }
5011  }
5012  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5013 
5014  /* checks, if cut is violated enough */
5015  if( SCIPisCutEfficacious(scip, sol, row) )
5016  {
5017  if( cons != NULL )
5018  {
5019  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5020  }
5021  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5022  (*ncuts)++;
5023  }
5024  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5025  }
5026 
5027  /* frees temporary memory */
5028  SCIPfreeBufferArray(scip, &liftcoefs);
5029  SCIPfreeBufferArray(scip, &varsR);
5030  SCIPfreeBufferArray(scip, &varsF);
5031  SCIPfreeBufferArray(scip, &varsC2);
5032  SCIPfreeBufferArray(scip, &varsC1);
5033 
5034  return SCIP_OKAY;
5035 }
5036 
5037 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
5038 static
5040  SCIP* scip, /**< SCIP data structure */
5041  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5042  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5043  SCIP_VAR** vars, /**< variables in knapsack constraint */
5044  int nvars, /**< number of variables in knapsack constraint */
5045  int ntightened, /**< number of variables with tightened upper bound */
5046  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5047  SCIP_Longint capacity, /**< capacity of knapsack */
5048  SCIP_Real* solvals, /**< solution values of all problem variables */
5049  int* feassetvars, /**< variables in feasible set */
5050  int* nonfeassetvars, /**< variables not in feasible set */
5051  int nfeassetvars, /**< number of variables in feasible set */
5052  int nnonfeassetvars, /**< number of variables not in feasible set */
5053  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5054  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5055  int* ncuts /**< pointer to add up the number of found cuts */
5056  )
5057 {
5058  int* varsT1;
5059  int* varsT2;
5060  int* varsF;
5061  int* varsR;
5062  int* liftcoefs;
5063  SCIP_Real cutact;
5064  int nvarsT1;
5065  int nvarsT2;
5066  int nvarsF;
5067  int nvarsR;
5068  int liftrhs;
5069  int j;
5070 
5071  assert( cutoff != NULL );
5072  *cutoff = FALSE;
5073 
5074  /* allocates temporary memory */
5075  SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5076  SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5077  SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5078  SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5079  SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5080 
5081  /* 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
5082  * as follows
5083  * T_2 = { j in T : x*_j = 1 } and
5084  * T_1 = T\T_2
5085  */
5086  getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5087  assert(nvarsT1 + nvarsT2 == nfeassetvars);
5088 
5089  /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5090  if( nvarsT1 == 0 && nvarsT2 > 0)
5091  {
5092  SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5093  assert(nvarsT1 == 1);
5094  }
5095  assert(nvarsT2 == 0 || nvarsT1 > 0);
5096 
5097  /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5098  * R = { j in N\T : x*_j = 0 } and
5099  * F = (N\T)\F
5100  */
5101  getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5102  assert(nvarsF + nvarsR == nnonfeassetvars);
5103  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5104 
5105  /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5106  * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5107  * is included in the sorting routine)
5108  */
5109  SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5110 
5111  /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5112  *
5113  * 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 }
5114  *
5115  * 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
5116  *
5117  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5118  *
5119  * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5120  * up-lifting for the variabels in R according to the second level lifting sequence
5121  */
5122  SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5123  nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5124 
5125  /* checks, if lifting yielded a violated cut */
5126  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5127  {
5128  SCIP_ROW* row;
5129  char name[SCIP_MAXSTRLEN];
5130 
5131  /* creates LP row */
5132  assert( cons == NULL || sepa == NULL );
5133  if( cons != NULL )
5134  {
5136  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5137  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5138  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5139  }
5140  else if ( sepa != NULL )
5141  {
5142  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5143  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5144  }
5145  else
5146  {
5147  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5148  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5149  }
5150 
5151  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5152  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5153  assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5154  for( j = 0; j < nvarsT1; j++ )
5155  {
5156  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5157  }
5158  for( j = 0; j < nvarsT2; j++ )
5159  {
5160  if( liftcoefs[varsT2[j]] > 0 )
5161  {
5162  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5163  }
5164  }
5165  for( j = 0; j < nvarsF; j++ )
5166  {
5167  if( liftcoefs[varsF[j]] > 0 )
5168  {
5169  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5170  }
5171  }
5172  for( j = 0; j < nvarsR; j++ )
5173  {
5174  if( liftcoefs[varsR[j]] > 0 )
5175  {
5176  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5177  }
5178  }
5179  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5180 
5181  /* checks, if cut is violated enough */
5182  if( SCIPisCutEfficacious(scip, sol, row) )
5183  {
5184  if( cons != NULL )
5185  {
5186  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5187  }
5188  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5189  (*ncuts)++;
5190  }
5191  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5192  }
5193 
5194  /* frees temporary memory */
5195  SCIPfreeBufferArray(scip, &liftcoefs);
5196  SCIPfreeBufferArray(scip, &varsR);
5197  SCIPfreeBufferArray(scip, &varsF);
5198  SCIPfreeBufferArray(scip, &varsT2);
5199  SCIPfreeBufferArray(scip, &varsT1);
5200 
5201  return SCIP_OKAY;
5202 }
5203 
5204 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5205 static
5207  SCIP* scip, /**< SCIP data structure */
5208  SCIP_CONS* cons, /**< constraint that originates the knapsack problem, or NULL */
5209  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5210  SCIP_VAR** vars, /**< variables in knapsack constraint */
5211  int nvars, /**< number of variables in knapsack constraint */
5212  int ntightened, /**< number of variables with tightened upper bound */
5213  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5214  SCIP_Longint capacity, /**< capacity of knapsack */
5215  SCIP_Real* solvals, /**< solution values of all problem variables */
5216  int* mincovervars, /**< mincover variables */
5217  int* nonmincovervars, /**< nonmincover variables */
5218  int nmincovervars, /**< number of mincover variables */
5219  int nnonmincovervars, /**< number of nonmincover variables */
5220  SCIP_Longint mincoverweight, /**< weight of minimal cover */
5221  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5222  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5223  int* ncuts /**< pointer to add up the number of found cuts */
5224  )
5225 {
5226  SCIP_Real* realliftcoefs;
5227  SCIP_Real cutact;
5228  int liftrhs;
5229 
5230  assert( cutoff != NULL );
5231  *cutoff = FALSE;
5232  cutact = 0.0;
5233 
5234  /* allocates temporary memory */
5235  SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5236 
5237  /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5238  *
5239  * S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5240  *
5241  * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5242  *
5243  * S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 },
5244  *
5245  * uses superadditive up-lifting for the variables in N\C.
5246  */
5247  SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5248  nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5249  liftrhs = nmincovervars - 1;
5250 
5251  /* checks, if lifting yielded a violated cut */
5252  if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5253  {
5254  SCIP_ROW* row;
5255  char name[SCIP_MAXSTRLEN];
5256  int j;
5257 
5258  /* creates LP row */
5259  assert( cons == NULL || sepa == NULL );
5260  if ( cons != NULL )
5261  {
5263  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5264  cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5265  cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5266  }
5267  else if ( sepa != NULL )
5268  {
5269  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5270  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5271  }
5272  else
5273  {
5274  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5275  SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5276  }
5277 
5278  /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5279  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5280  assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5281  for( j = 0; j < nmincovervars; j++ )
5282  {
5283  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5284  }
5285  for( j = 0; j < nnonmincovervars; j++ )
5286  {
5287  assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5288  if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5289  {
5290  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5291  }
5292  }
5293  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5294 
5295  /* checks, if cut is violated enough */
5296  if( SCIPisCutEfficacious(scip, sol, row) )
5297  {
5298  if( cons != NULL )
5299  {
5300  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5301  }
5302  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5303  (*ncuts)++;
5304  }
5305  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5306  }
5307 
5308  /* frees temporary memory */
5309  SCIPfreeBufferArray(scip, &realliftcoefs);
5310 
5311  return SCIP_OKAY;
5312 }
5313 
5314 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5315  * 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
5316  * C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5317  * note that all variables with x*_j = 1 will be removed last
5318  */
5319 static
5321  SCIP* scip, /**< SCIP data structure */
5322  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5323  SCIP_Longint capacity, /**< capacity of knapsack */
5324  SCIP_Real* solvals, /**< solution values of all problem variables */
5325  int* covervars, /**< pointer to store cover variables */
5326  int* noncovervars, /**< pointer to store noncover variables */
5327  int* ncovervars, /**< pointer to store number of cover variables */
5328  int* nnoncovervars, /**< pointer to store number of noncover variables */
5329  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5330  SCIP_Bool modtransused /**< TRUE if mod trans sepa prob was used to find cover */
5331  )
5332 {
5333  SORTKEYPAIR** sortkeypairs;
5334  SORTKEYPAIR** sortkeypairssorted;
5335  SCIP_Longint minweight;
5336  int nsortkeypairs;
5337  int minweightidx;
5338  int j;
5339  int k;
5340 
5341  assert(scip != NULL);
5342  assert(covervars != NULL);
5343  assert(noncovervars != NULL);
5344  assert(ncovervars != NULL);
5345  assert(*ncovervars > 0);
5346  assert(nnoncovervars != NULL);
5347  assert(*nnoncovervars >= 0);
5348  assert(coverweight != NULL);
5349  assert(*coverweight > 0);
5350  assert(*coverweight > capacity);
5351 
5352  /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5353  * order */
5354  nsortkeypairs = *ncovervars;
5355  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5356  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5357 
5358  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5359  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5360  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5361  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5362  */
5363  assert(*ncovervars == nsortkeypairs);
5364  if( modtransused )
5365  {
5366  for( j = 0; j < *ncovervars; j++ )
5367  {
5368  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5369  sortkeypairssorted[j] = sortkeypairs[j];
5370 
5371  sortkeypairs[j]->key1 = solvals[covervars[j]];
5372  sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5373  }
5374  }
5375  else
5376  {
5377  for( j = 0; j < *ncovervars; j++ )
5378  {
5379  SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5380  sortkeypairssorted[j] = sortkeypairs[j];
5381 
5382  sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5383  sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5384  }
5385  }
5386  SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5387 
5388  /* gets j' with a_j' = min{ a_j : j in C } */
5389  minweightidx = 0;
5390  minweight = weights[covervars[minweightidx]];
5391  for( j = 1; j < *ncovervars; j++ )
5392  {
5393  if( weights[covervars[j]] <= minweight )
5394  {
5395  minweightidx = j;
5396  minweight = weights[covervars[minweightidx]];
5397  }
5398  }
5399  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5400  assert(minweight > 0 && minweight <= *coverweight);
5401 
5402  j = 0;
5403  /* removes variables from C until the remaining variables form a minimal cover */
5404  while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5405  {
5406  assert(minweightidx >= j);
5407  assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5408 
5409  /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5410  if( (*coverweight) - weights[covervars[j]] <= capacity )
5411  {
5412  ++j;
5413  continue;
5414  }
5415 
5416  /* adds j to N\C */
5417  noncovervars[*nnoncovervars] = covervars[j];
5418  (*nnoncovervars)++;
5419 
5420  /* removes j from C */
5421  (*coverweight) -= weights[covervars[j]];
5422  for( k = j; k < (*ncovervars) - 1; k++ )
5423  covervars[k] = covervars[k+1];
5424  (*ncovervars)--;
5425 
5426  /* updates j' with a_j' = min{ a_j : j in C } */
5427  if( j == minweightidx )
5428  {
5429  minweightidx = 0;
5430  minweight = weights[covervars[minweightidx]];
5431  for( k = 1; k < *ncovervars; k++ )
5432  {
5433  if( weights[covervars[k]] <= minweight )
5434  {
5435  minweightidx = k;
5436  minweight = weights[covervars[minweightidx]];
5437  }
5438  }
5439  assert(minweight > 0 && minweight <= *coverweight);
5440  assert(minweightidx >= 0 && minweightidx < *ncovervars);
5441  }
5442  else
5443  {
5444  assert(minweightidx > j);
5445  minweightidx--;
5446  }
5447  /* j needs to stay the same */
5448  }
5449  assert((*coverweight) > capacity);
5450  assert((*coverweight) - minweight <= capacity);
5451 
5452  /* frees temporary memory */
5453  for( j = nsortkeypairs-1; j >= 0; j-- )
5454  SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5455  SCIPfreeBufferArray(scip, &sortkeypairssorted);
5456  SCIPfreeBufferArray(scip, &sortkeypairs);
5457 
5458  return SCIP_OKAY;
5459 }
5460 
5461 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5462  * they were chosen to be in C_init:
5463  * non-increasing (1 - x*_j)/a_j, if transformed separation problem was used to find C_init
5464  * non-increasing (1 - x*_j), if modified transformed separation problem was used to find C_init.
5465  * separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5466  * and all subsequent feasible sets.
5467  */
5468 static
5470  SCIP* scip, /**< SCIP data structure */
5471  SCIP_CONS* cons, /**< constraint that originates the knapsack problem */
5472  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5473  SCIP_VAR** vars, /**< variables in knapsack constraint */
5474  int nvars, /**< number of variables in knapsack constraint */
5475  int ntightened, /**< number of variables with tightened upper bound */
5476  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5477  SCIP_Longint capacity, /**< capacity of knapsack */
5478  SCIP_Real* solvals, /**< solution values of all problem variables */
5479  int* covervars, /**< pointer to store cover variables */
5480  int* noncovervars, /**< pointer to store noncover variables */
5481  int* ncovervars, /**< pointer to store number of cover variables */
5482  int* nnoncovervars, /**< pointer to store number of noncover variables */
5483  SCIP_Longint* coverweight, /**< pointer to store weight of cover */
5484  SCIP_Bool modtransused, /**< TRUE if mod trans sepa prob was used to find cover */
5485  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5486  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
5487  int* ncuts /**< pointer to add up the number of found cuts */
5488  )
5489 {
5490  SCIP_Real* sortkeys;
5491  int j;
5492  int k;
5493 
5494  assert(scip != NULL);
5495  assert(covervars != NULL);
5496  assert(noncovervars != NULL);
5497  assert(ncovervars != NULL);
5498  assert(*ncovervars > 0);
5499  assert(nnoncovervars != NULL);
5500  assert(*nnoncovervars >= 0);
5501  assert(coverweight != NULL);
5502  assert(*coverweight > 0);
5503  assert(*coverweight > capacity);
5504  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5505  assert(cutoff != NULL);
5506 
5507  *cutoff = FALSE;
5508 
5509  /* allocates temporary memory */
5510  SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5511 
5512  /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5513  * such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|, if trans separation problem was used to find C
5514  * such that (1 - x*_1) >= ... >= (1 - x*_|C|), if modified trans separation problem was used to find C
5515  * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5516  */
5517  if( modtransused )
5518  {
5519  for( j = 0; j < *ncovervars; j++ )
5520  {
5521  sortkeys[j] = solvals[covervars[j]];
5522  assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5523  }
5524  }
5525  else
5526  {
5527  for( j = 0; j < *ncovervars; j++ )
5528  {
5529  sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5530  assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5531  }
5532  }
5533  SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5534 
5535  /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5536  * in addition to an extended weight inequality this gives cardinality inequalities */
5537  while( *ncovervars >= 2 )
5538  {
5539  /* adds first element of C_init to N\C_init */
5540  noncovervars[*nnoncovervars] = covervars[0];
5541  (*nnoncovervars)++;
5542 
5543  /* removes first element from C_init */
5544  (*coverweight) -= weights[covervars[0]];
5545  for( k = 0; k < (*ncovervars) - 1; k++ )
5546  covervars[k] = covervars[k+1];
5547  (*ncovervars)--;
5548 
5549  assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5550  if( (*coverweight) <= capacity )
5551  {
5552  SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5553  covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5554  }
5555 
5556  /* stop if cover is too large */
5557  if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5558  break;
5559  }
5560 
5561  /* frees temporary memory */
5562  SCIPfreeBufferArray(scip, &sortkeys);
5563 
5564  return SCIP_OKAY;
5565 }
5566 
5567 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
5569  SCIP* scip, /**< SCIP data structure */
5570  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5571  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5572  SCIP_VAR** vars, /**< variables in knapsack constraint */
5573  int nvars, /**< number of variables in knapsack constraint */
5574  SCIP_Longint* weights, /**< weights of variables in knapsack constraint */
5575  SCIP_Longint capacity, /**< capacity of knapsack */
5576  SCIP_SOL* sol, /**< primal SCIP solution to separate, NULL for current LP solution */
5577  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
5578  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff has been detected */
5579  int* ncuts /**< pointer to add up the number of found cuts */
5580  )
5581 {
5582  SCIP_Real* solvals;
5583  int* covervars;
5584  int* noncovervars;
5585  SCIP_Bool coverfound;
5586  SCIP_Bool fractional;
5587  SCIP_Bool modtransused;
5588  SCIP_Longint coverweight;
5589  int ncovervars;
5590  int nnoncovervars;
5591  int ntightened;
5592 
5593  assert(scip != NULL);
5594  assert(capacity >= 0);
5595  assert(cutoff != NULL);
5596  assert(ncuts != NULL);
5597 
5598  *cutoff = FALSE;
5599 
5600  if( nvars == 0 )
5601  return SCIP_OKAY;
5602 
5603  assert(vars != NULL);
5604  assert(nvars > 0);
5605  assert(weights != NULL);
5606 
5607  /* increase age of constraint (age is reset to zero, if a cut was found) */
5608  if( cons != NULL )
5609  {
5610  SCIP_CALL( SCIPincConsAge(scip, cons) );
5611  }
5612 
5613  /* allocates temporary memory */
5614  SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5615  SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5616  SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5617 
5618  /* gets solution values of all problem variables */
5619  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5620 
5621 #ifdef SCIP_DEBUG
5622  {
5623  int i;
5624 
5625  SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5626  cons == NULL ? "-" : SCIPconsGetName(cons));
5627  for( i = 0; i < nvars; ++i )
5628  {
5629  SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5630  }
5631  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5632  }
5633 #endif
5634 
5635  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5636  */
5637  if( usegubs )
5638  {
5639  SCIP_GUBSET* gubset;
5640 
5641  SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5642 
5643  /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5644  SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5645 
5646  /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5647  SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5648  assert(gubset->ngubconss <= nvars);
5649 
5650  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5651  * MODIFIED transformed separation problem and taking into account the following fixing:
5652  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5653  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5654  * if one exists
5655  */
5656  modtransused = TRUE;
5657  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5658  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5659 
5660  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5661 
5662  /* if x* is not fractional we stop the separation routine */
5663  if( !fractional )
5664  {
5665  SCIPdebugMsg(scip, " LMCI1-GUB terminated by no variable with fractional LP value.\n");
5666 
5667  /* frees memory for GUB set data structure */
5668  GUBsetFree(scip, &gubset);
5669 
5670  goto TERMINATE;
5671  }
5672 
5673  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5674  if( coverfound )
5675  {
5676  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5677  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5678  */
5679  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5680  &nnoncovervars, &coverweight, modtransused) );
5681 
5682  /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5683  if( gubset->ngubconss < nvars )
5684  {
5685  /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5686  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5687  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5688  }
5689  else
5690  {
5691  /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5692  * GUB information
5693  */
5694  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5695  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5696  }
5697  }
5698 
5699  /* frees memory for GUB set data structure */
5700  GUBsetFree(scip, &gubset);
5701  }
5702  else
5703  {
5704  /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5705  * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5706  */
5707 
5708  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5709  * MODIFIED transformed separation problem and taking into account the following fixing:
5710  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5711  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5712  * if one exists
5713  */
5714  SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5715  modtransused = TRUE;
5716  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5717  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5718  assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5719 
5720  /* if x* is not fractional we stop the separation routine */
5721  if( !fractional )
5722  goto TERMINATE;
5723 
5724  /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5725  if( coverfound )
5726  {
5727  /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5728  * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5729  */
5730  SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5731  &nnoncovervars, &coverweight, modtransused) );
5732 
5733  /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5734  SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5735  solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5736 
5737  if( USESUPADDLIFT ) /*lint !e506 !e774*/
5738  {
5739  SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5740  /* separates lifted minimal cover inequalities using superadditive up-lifting */
5741  SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5742  solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5743  }
5744  }
5745  }
5746 
5747  /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5748  if ( ! (*cutoff) )
5749  {
5750  /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5751  * transformed separation problem and taking into account the following fixing:
5752  * j in C_init, if j in N_1 = {j in N : x*_j = 1} and
5753  * j in N\C_init, if j in N_0 = {j in N : x*_j = 0},
5754  * if one exists
5755  */
5756  SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5757  modtransused = FALSE;
5758  SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5759  &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5760  assert(fractional);
5761  assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5762 
5763  /* if no cover was found we stop the separation routine */
5764  if( coverfound )
5765  {
5766  /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5767  * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5768  * up- and down-lifting for this feasible set and all subsequent feasible sets.
5769  */
5770  SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5771  &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5772  }
5773  }
5774 
5775  TERMINATE:
5776  /* frees temporary memory */
5777  SCIPfreeBufferArray(scip, &noncovervars);
5778  SCIPfreeBufferArray(scip, &covervars);
5779  SCIPfreeBufferArray(scip, &solvals);
5780 
5781  return SCIP_OKAY;
5782 }
5783 
5784 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
5786  SCIP* scip, /**< SCIP data structure */
5787  SCIP_CONS* cons, /**< originating constraint of the knapsack problem, or NULL */
5788  SCIP_SEPA* sepa, /**< originating separator of the knapsack problem, or NULL */
5789  int nknapvars, /**< number of variables in the continuous knapsack constraint */
5790  SCIP_VAR** knapvars, /**< variables in the continuous knapsack constraint */
5791  SCIP_Real* knapvals, /**< coefficients of the variables in the continuous knapsack constraint */
5792  SCIP_Real valscale, /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5793  SCIP_Real rhs, /**< right hand side of the continuous knapsack constraint */
5794  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
5795  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
5796  int* ncuts /**< pointer to add up the number of found cuts */
5797  )
5798 {
5799  SCIP_VAR** binvars;
5800  SCIP_VAR** consvars;
5801  SCIP_Real* binvals;
5802  SCIP_Longint* consvals;
5803  SCIP_Longint minact;
5804  SCIP_Longint maxact;
5805  SCIP_Real intscalar;
5806  SCIP_Bool success;
5807  int nbinvars;
5808  int nconsvars;
5809  int i;
5810 
5811  int* tmpindices;
5812  int tmp;
5813  SCIP_CONSHDLR* conshdlr;
5814  SCIP_CONSHDLRDATA* conshdlrdata;
5815  SCIP_Bool noknapsackconshdlr;
5816  SCIP_Bool usegubs;
5817 
5818  assert(nknapvars > 0);
5819  assert(knapvars != NULL);
5820  assert(cutoff != NULL);
5821 
5822  tmpindices = NULL;
5823 
5824  SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5825  SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5826 
5827  binvars = SCIPgetVars(scip);
5828 
5829  /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5830  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5831 
5832  *cutoff = FALSE;
5833 
5834  if( nbinvars == 0 )
5835  return SCIP_OKAY;
5836 
5837  /* set up data structures */
5838  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5839  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5840 
5841  /* get conshdlrdata to use cleared memory */
5842  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5843  if( conshdlr == NULL )
5844  {
5845  noknapsackconshdlr = TRUE;
5846  usegubs = DEFAULT_USEGUBS;
5847 
5848  SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5849  BMSclearMemoryArray(binvals, nbinvars);
5850  }
5851  else
5852  {
5853  noknapsackconshdlr = FALSE;
5854  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5855  assert(conshdlrdata != NULL);
5856  usegubs = conshdlrdata->usegubs;
5857 
5858  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5859 
5860  /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5861  * change their types to SCIP_VARTYPE_BINARY during presolving
5862  */
5863  if( conshdlrdata->reals1size == 0 )
5864  {
5865  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5866  conshdlrdata->reals1size = 1;
5867  conshdlrdata->reals1[0] = 0.0;
5868  }
5869 
5870  assert(conshdlrdata->reals1size > 0);
5871 
5872  /* next if condition should normally not be true, because it means that presolving has created more binary
5873  * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5874  * transform all integers into their binary representation then it maybe happens
5875  */
5876  if( conshdlrdata->reals1size < nbinvars )
5877  {
5878  int oldsize = conshdlrdata->reals1size;
5879 
5880  conshdlrdata->reals1size = nbinvars;
5881  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5882  BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5883  }
5884  binvals = conshdlrdata->reals1;
5885 
5886  /* check for cleared array, all entries have to be zero */
5887 #ifndef NDEBUG
5888  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5889  {
5890  assert(binvals[tmp] == 0);
5891  }
5892 #endif
5893  }
5894 
5895  tmp = 0;
5896 
5897  /* relax continuous knapsack constraint:
5898  * 1. make all variables binary:
5899  * if x_j is continuous or integer variable substitute:
5900  * - a_j < 0: x_j = lb or x_j = b*z + d with variable lower bound b*z + d with binary variable z
5901  * - a_j > 0: x_j = ub or x_j = b*z + d with variable upper bound b*z + d with binary variable z
5902  * 2. convert coefficients of all variables to positive integers:
5903  * - scale all coefficients a_j to a~_j integral
5904  * - substitute x~_j = 1 - x_j if a~_j < 0
5905  */
5906 
5907  /* replace integer and continuous variables with binary variables */
5908  for( i = 0; i < nknapvars; i++ )
5909  {
5910  SCIP_VAR* var;
5911 
5912  var = knapvars[i];
5913 
5914  if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5915  {
5916  SCIP_Real solval;
5917  assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5918 
5919  solval = SCIPgetSolVal(scip, sol, var);
5920 
5921  /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5922  if( SCIPisFeasLT(scip, solval, 0.0 )
5923  || SCIPisFeasGT(scip, solval, 1.0) )
5924  {
5925  SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5926  solval, SCIPvarGetName(var));
5927  goto TERMINATE;
5928  }
5929 
5930  binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5931  if( !noknapsackconshdlr )
5932  {
5933  assert(tmpindices != NULL);
5934 
5935  tmpindices[tmp] = SCIPvarGetProbindex(var);
5936  ++tmp;
5937  }
5938  SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5939  }
5940  else if( valscale * knapvals[i] > 0.0 )
5941  {
5942  SCIP_VAR** zvlb;
5943  SCIP_Real* bvlb;
5944  SCIP_Real* dvlb;
5945  SCIP_Real bestlbsol;
5946  int bestlbtype;
5947  int nvlb;
5948  int j;
5949 
5950  /* a_j > 0: substitution with lb or vlb */
5951  nvlb = SCIPvarGetNVlbs(var);
5952  zvlb = SCIPvarGetVlbVars(var);
5953  bvlb = SCIPvarGetVlbCoefs(var);
5954  dvlb = SCIPvarGetVlbConstants(var);
5955 
5956  /* search for lb or vlb with maximal bound value */
5957  bestlbsol = SCIPvarGetLbGlobal(var);
5958  bestlbtype = -1;
5959  for( j = 0; j < nvlb; j++ )
5960  {
5961  /* use only numerical stable vlb with binary variable z */
5962  if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5963  {
5964  SCIP_Real vlbsol;
5965 
5966  if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5967  (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5968  {
5969  *cutoff = TRUE;
5970  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5972  bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5973  goto TERMINATE;
5974  }
5975 
5976  assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5977  vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5978  if( SCIPisGE(scip, vlbsol, bestlbsol) )
5979  {
5980  bestlbsol = vlbsol;
5981  bestlbtype = j;
5982  }
5983  }
5984  }
5985 
5986  /* if no lb or vlb with binary variable was found, we have to abort */
5987  if( SCIPisInfinity(scip, -bestlbsol) )
5988  goto TERMINATE;
5989 
5990  if( bestlbtype == -1 )
5991  {
5992  rhs -= valscale * knapvals[i] * bestlbsol;
5993  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5994  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5995  }
5996  else
5997  {
5998  assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5999  rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
6000  binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
6001 
6002  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
6003  goto TERMINATE;
6004 
6005  if( !noknapsackconshdlr )
6006  {
6007  assert(tmpindices != NULL);
6008 
6009  tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
6010  ++tmp;
6011  }
6012  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6013  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6014  bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
6015  SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
6016  }
6017  }
6018  else
6019  {
6020  SCIP_VAR** zvub;
6021  SCIP_Real* bvub;
6022  SCIP_Real* dvub;
6023  SCIP_Real bestubsol;
6024  int bestubtype;
6025  int nvub;
6026  int j;
6027 
6028  assert(valscale * knapvals[i] < 0.0);
6029 
6030  /* a_j < 0: substitution with ub or vub */
6031  nvub = SCIPvarGetNVubs(var);
6032  zvub = SCIPvarGetVubVars(var);
6033  bvub = SCIPvarGetVubCoefs(var);
6034  dvub = SCIPvarGetVubConstants(var);
6035 
6036  /* search for ub or vub with minimal bound value */
6037  bestubsol = SCIPvarGetUbGlobal(var);
6038  bestubtype = -1;
6039  for( j = 0; j < nvub; j++ )
6040  {
6041  /* use only numerical stable vub with active binary variable z */
6042  if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
6043  {
6044  SCIP_Real vubsol;
6045 
6046  if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
6047  (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
6048  {
6049  *cutoff = TRUE;
6050  SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
6052  bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
6053  goto TERMINATE;
6054  }
6055 
6056  assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
6057  vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
6058  if( SCIPisLE(scip, vubsol, bestubsol) )
6059  {
6060  bestubsol = vubsol;
6061  bestubtype = j;
6062  }
6063  }
6064  }
6065 
6066  /* if no ub or vub with binary variable was found, we have to abort */
6067  if( SCIPisInfinity(scip, bestubsol) )
6068  goto TERMINATE;
6069 
6070  if( bestubtype == -1 )
6071  {
6072  rhs -= valscale * knapvals[i] * bestubsol;
6073  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6074  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6075  }
6076  else
6077  {
6078  assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6079  rhs -= valscale * knapvals[i] * dvub[bestubtype];
6080  binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6081 
6082  if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6083  goto TERMINATE;
6084 
6085  if( !noknapsackconshdlr )
6086  {
6087  assert(tmpindices != NULL);
6088 
6089  tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6090  ++tmp;
6091  }
6092  SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6093  valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6094  bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6095  SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6096  }
6097  }
6098  }
6099 
6100  /* convert coefficients of all (now binary) variables to positive integers:
6101  * - make all coefficients integral
6102  * - make all coefficients positive (substitute negated variable)
6103  */
6104  nconsvars = 0;
6105 
6106  /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6107  * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6108  */
6110  KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6111  SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6112 
6113  /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6114  if( !success )
6115  intscalar = 1.0;
6116 
6117  /* make all coefficients integral and positive:
6118  * - scale a~_j = a_j * intscalar
6119  * - substitute x~_j = 1 - x_j if a~_j < 0
6120  */
6121  rhs = rhs * intscalar;
6122 
6123  SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6124  minact = 0;
6125  maxact = 0;
6126  for( i = 0; i < nbinvars; i++ )
6127  {
6128  SCIP_VAR* var;
6129  SCIP_Longint val;
6130 
6131  val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6132  if( val == 0 )
6133  continue;
6134 
6135  if( val > 0 )
6136  {
6137  var = binvars[i];
6138  SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6139  val, SCIPvarGetName(var), binvals[i], rhs);
6140  }
6141  else
6142  {
6143  assert(val < 0);
6144 
6145  SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6146  val = -val; /*lint !e2704*/
6147  rhs += val;
6148  SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6149  -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6150  }
6151 
6152  if( SCIPvarGetLbLocal(var) > 0.5 )
6153  minact += val;
6154  if( SCIPvarGetUbLocal(var) > 0.5 )
6155  maxact += val;
6156  consvals[nconsvars] = val;
6157  consvars[nconsvars] = var;
6158  nconsvars++;
6159  }
6160 
6161  if( nconsvars > 0 )
6162  {
6163  SCIP_Longint capacity;
6164 
6165  assert(consvars != NULL);
6166  assert(consvals != NULL);
6167  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6168 
6169 #ifdef SCIP_DEBUG
6170  {
6171  SCIP_Real act;
6172 
6173  SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6174  act = 0.0;
6175  for( i = 0; i < nconsvars; ++i )
6176  {
6177  SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6178  SCIPgetSolVal(scip, sol, consvars[i]));
6179  act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6180  }
6181  SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6182  capacity, rhs, act, minact, maxact);
6183  }
6184 #endif
6185 
6186  if( minact > capacity )
6187  {
6188  SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6189  *cutoff = TRUE;
6190  goto TERMINATE;
6191  }
6192 
6193  if( maxact > capacity )
6194  {
6195  /* separate lifted cut from relaxed knapsack constraint */
6196  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6197  }
6198  }
6199 
6200  TERMINATE:
6201  /* free data structures */
6202  if( noknapsackconshdlr)
6203  {
6204  SCIPfreeBufferArray(scip, &binvals);
6205  }
6206  else
6207  {
6208  /* clear binvals */
6209  for( --tmp; tmp >= 0; --tmp)
6210  {
6211  assert(tmpindices != NULL);
6212  binvals[tmpindices[tmp]] = 0;
6213  }
6214  SCIPfreeBufferArray(scip, &tmpindices);
6215  }
6216  SCIPfreeBufferArray(scip, &consvals);
6217  SCIPfreeBufferArray(scip, &consvars);
6218 
6219  return SCIP_OKAY;
6220 }
6221 
6222 /** separates given knapsack constraint */
6223 static
6225  SCIP* scip, /**< SCIP data structure */
6226  SCIP_CONS* cons, /**< knapsack constraint */
6227  SCIP_SOL* sol, /**< primal SCIP solution, NULL for current LP solution */
6228  SCIP_Bool sepacuts, /**< should knapsack cuts be separated? */
6229  SCIP_Bool usegubs, /**< should GUB information be used for separation? */
6230  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
6231  int* ncuts /**< pointer to add up the number of found cuts */
6232  )
6233 {
6234  SCIP_CONSDATA* consdata;
6235  SCIP_Bool violated;
6236 
6237  assert(ncuts != NULL);
6238  assert(cutoff != NULL);
6239  *cutoff = FALSE;
6240 
6241  consdata = SCIPconsGetData(cons);
6242  assert(consdata != NULL);
6243 
6244  SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6245 
6246  /* check knapsack constraint itself for feasibility */
6247  SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6248 
6249  if( violated )
6250  {
6251  /* add knapsack constraint as LP row to the LP */
6252  SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6253  (*ncuts)++;
6254  }
6255  else if( sepacuts )
6256  {
6257  SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6258  consdata->capacity, sol, usegubs, cutoff, ncuts) );
6259  }
6260 
6261  return SCIP_OKAY;
6262 }
6263 
6264 /** adds coefficient to constraint data */
6265 static
6267  SCIP* scip, /**< SCIP data structure */
6268  SCIP_CONS* cons, /**< knapsack constraint */
6269  SCIP_VAR* var, /**< variable to add to knapsack */
6270  SCIP_Longint weight /**< weight of variable in knapsack */
6271  )
6272 {
6273  SCIP_CONSDATA* consdata;
6275  consdata = SCIPconsGetData(cons);
6276  assert(consdata != NULL);
6277  assert(SCIPvarIsBinary(var));
6278  assert(weight > 0);
6279 
6280  /* add the new coefficient to the LP row */
6281  if( consdata->row != NULL )
6282  {
6283  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6284  }
6285 
6286  /* check for fixed variable */
6287  if( SCIPvarGetLbGlobal(var) > 0.5 )
6288  {
6289  /* variable is fixed to one: reduce capacity */
6290  consdata->capacity -= weight;
6291  }
6292  else if( SCIPvarGetUbGlobal(var) > 0.5 )
6293  {
6294  SCIP_Bool negated;
6295 
6296  /* get binary representative of variable */
6297  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6298 
6299  /* insert coefficient */
6300  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6301  consdata->vars[consdata->nvars] = var;
6302  consdata->weights[consdata->nvars] = weight;
6303  consdata->nvars++;
6304 
6305  /* capture variable */
6306  SCIP_CALL( SCIPcaptureVar(scip, var) );
6307 
6308  /* install the rounding locks of variable */
6309  SCIP_CALL( lockRounding(scip, cons, var) );
6310 
6311  /* catch events */
6312  if( SCIPconsIsTransformed(cons) )
6313  {
6314  SCIP_CONSHDLRDATA* conshdlrdata;
6315 
6316  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6317  assert(conshdlrdata != NULL);
6318  SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6320  conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6321  &consdata->eventdata[consdata->nvars-1]->filterpos) );
6322 
6323  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6324  consdata->existmultaggr = TRUE;
6325 
6326  /* mark constraint to be propagated and presolved */
6327  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6328  consdata->presolvedtiming = 0;
6329  consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6330  }
6331 
6332  /* update weight sums */
6333  updateWeightSums(consdata, var, weight);
6334 
6335  consdata->sorted = FALSE;
6336  consdata->cliquepartitioned = FALSE;
6337  consdata->negcliquepartitioned = FALSE;
6338  consdata->merged = FALSE;
6339  }
6340 
6341  return SCIP_OKAY;
6342 }
6343 
6344 /** deletes coefficient at given position from constraint data */
6345 static
6347  SCIP* scip, /**< SCIP data structure */
6348  SCIP_CONS* cons, /**< knapsack constraint */
6349  int pos /**< position of coefficient to delete */
6350  )
6351 {
6352  SCIP_CONSDATA* consdata;
6353  SCIP_VAR* var;
6355  consdata = SCIPconsGetData(cons);
6356  assert(consdata != NULL);
6357  assert(0 <= pos && pos < consdata->nvars);
6358 
6359  var = consdata->vars[pos];
6360  assert(var != NULL);
6361  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6362 
6363  /* delete the coefficient from the LP row */
6364  if( consdata->row != NULL )
6365  {
6366  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6367  }
6368 
6369  /* remove the rounding locks of variable */
6370  SCIP_CALL( unlockRounding(scip, cons, var) );
6371 
6372  /* drop events and mark constraint to be propagated and presolved */
6373  if( SCIPconsIsTransformed(cons) )
6374  {
6375  SCIP_CONSHDLRDATA* conshdlrdata;
6376 
6377  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6378  assert(conshdlrdata != NULL);
6380  conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6381  SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6382 
6383  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6384  consdata->presolvedtiming = 0;
6385  consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6386  }
6387 
6388  /* decrease weight sums */
6389  updateWeightSums(consdata, var, -consdata->weights[pos]);
6390 
6391  /* move the last variable to the free slot */
6392  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6393  consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6394  if( consdata->eventdata != NULL )
6395  consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6396 
6397  /* release variable */
6398  SCIP_CALL( SCIPreleaseVar(scip, &var) );
6399 
6400  /* try to use old clique partitions */
6401  if( consdata->cliquepartitioned )
6402  {
6403  assert(consdata->cliquepartition != NULL);
6404  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6405  * change the clique number */
6406  if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6407  {
6408  int oldcliqenum;
6409 
6410  oldcliqenum = consdata->cliquepartition[pos];
6411  consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6412 
6413  /* the following if and else cases assure that we have increasing clique numbers */
6414  if( consdata->cliquepartition[pos] > pos )
6415  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6416  else
6417  {
6418  int i;
6419  int cliquenumbefore;
6420 
6421  /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6422  * occurs the same as the old one is still in the cliquepartition */
6423  if( oldcliqenum > consdata->cliquepartition[pos] )
6424  {
6425  for( i = 0; i < consdata->nvars; ++i )
6426  if( oldcliqenum == consdata->cliquepartition[i] )
6427  break;
6428  else if( oldcliqenum < consdata->cliquepartition[i] )
6429  {
6430  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6431  break;
6432  }
6433  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6434  * the biggest index, so decrease the number of cliques
6435  */
6436  if( i == consdata->nvars )
6437  --(consdata->ncliques);
6438  }
6439  /* if the old clique number was smaller than the new one we have to check the front for an element with
6440  * clique number minus 1 */
6441  else if( oldcliqenum < consdata->cliquepartition[pos] )
6442  {
6443  cliquenumbefore = consdata->cliquepartition[pos] - 1;
6444  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6445 
6446  if( i < cliquenumbefore )
6447  consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6448  }
6449  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6450  else if( pos == consdata->nvars - 1)
6451  {
6452  cliquenumbefore = consdata->cliquepartition[pos];
6453  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6454 
6455  if( i < cliquenumbefore )
6456  --(consdata->ncliques);
6457  }
6458  /* if the old clique number is equal to the new one the cliquepartition should be ok */
6459  }
6460  }
6461  else
6462  --(consdata->ncliques);
6463  }
6464 
6465  if( consdata->negcliquepartitioned )
6466  {
6467  assert(consdata->negcliquepartition != NULL);
6468  /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6469  * change the clique number */
6470  if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6471  {
6472  int oldcliqenum;
6473 
6474  oldcliqenum = consdata->negcliquepartition[pos];
6475  consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6476 
6477  /* the following if and else cases assure that we have increasing clique numbers */
6478  if( consdata->negcliquepartition[pos] > pos )
6479  consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6480  else
6481  {
6482  int i;
6483  int cliquenumbefore;
6484 
6485  /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6486  * occurs, the same as the old one occurs */
6487  if( oldcliqenum > consdata->negcliquepartition[pos] )
6488  {
6489  for( i = 0; i < consdata->nvars; ++i )
6490  if( oldcliqenum == consdata->negcliquepartition[i] )
6491  break;
6492  else if( oldcliqenum < consdata->negcliquepartition[i] )
6493  {
6494  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6495  break;
6496  }
6497  /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6498  * the biggest index, so decrease the number of negated cliques
6499  */
6500  if( i == consdata->nvars )
6501  --(consdata->nnegcliques);
6502  }
6503  /* if the old clique number was smaller than the new one we have to check the front for an element with
6504  * clique number minus 1 */
6505  else if( oldcliqenum < consdata->negcliquepartition[pos] )
6506  {
6507  cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6508  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6509 
6510  if( i < cliquenumbefore )
6511  consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6512  }
6513  /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6514  else if( pos == consdata->nvars - 1)
6515  {
6516  cliquenumbefore = consdata->negcliquepartition[pos];
6517  for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6518 
6519  if( i < cliquenumbefore )
6520  --(consdata->nnegcliques);
6521  }
6522  /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6523  }
6524  }
6525  else
6526  --(consdata->nnegcliques);
6527  }
6528 
6529  --(consdata->nvars);
6530 
6531  return SCIP_OKAY;
6532 }
6533 
6534 /** removes all items with weight zero from knapsack constraint */
6535 static
6537  SCIP* scip, /**< SCIP data structure */
6538  SCIP_CONS* cons /**< knapsack constraint */
6539  )
6540 {
6541  SCIP_CONSDATA* consdata;
6542  int v;
6543 
6544  consdata = SCIPconsGetData(cons);
6545  assert(consdata != NULL);
6546 
6547  for( v = consdata->nvars-1; v >= 0; --v )
6548  {
6549  if( consdata->weights[v] == 0 )
6550  {
6551  SCIP_CALL( delCoefPos(scip, cons, v) );
6552  }
6553  }
6554 
6555  return SCIP_OKAY;
6556 }
6557 
6558 /* perform deletion of variables in all constraints of the constraint handler */
6559 static
6561  SCIP* scip, /**< SCIP data structure */
6562  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6563  SCIP_CONS** conss, /**< array of constraints */
6564  int nconss /**< number of constraints */
6565  )
6566 {
6567  SCIP_CONSDATA* consdata;
6568  int i;
6569  int v;
6570 
6571  assert(scip != NULL);
6572  assert(conshdlr != NULL);
6573  assert(conss != NULL);
6574  assert(nconss >= 0);
6575  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6576 
6577  /* iterate over all constraints */
6578  for( i = 0; i < nconss; i++ )
6579  {
6580  consdata = SCIPconsGetData(conss[i]);
6581 
6582  /* constraint is marked, that some of its variables were deleted */
6583  if( consdata->varsdeleted )
6584  {
6585  /* iterate over all variables of the constraint and delete them from the constraint */
6586  for( v = consdata->nvars - 1; v >= 0; --v )
6587  {
6588  if( SCIPvarIsDeleted(consdata->vars[v]) )
6589  {
6590  SCIP_CALL( delCoefPos(scip, conss[i], v) );
6591  }
6592  }
6593  consdata->varsdeleted = FALSE;
6594  }
6595  }
6596 
6597  return SCIP_OKAY;
6598 }
6599 
6600 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6601 static
6603  SCIP* scip, /**< SCIP data structure */
6604  SCIP_CONS* cons, /**< knapsack constraint */
6605  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
6606  )
6607 {
6608  SCIP_CONSDATA* consdata;
6609  int v;
6610  int prev;
6611 
6612  assert(scip != NULL);
6613  assert(cons != NULL);
6614  assert(cutoff != NULL);
6615 
6616  consdata = SCIPconsGetData(cons);
6617  assert(consdata != NULL);
6618 
6619  *cutoff = FALSE;
6620 
6621  if( consdata->merged )
6622  return SCIP_OKAY;
6623 
6624  if( consdata->nvars <= 1 )
6625  {
6626  consdata->merged = TRUE;
6627  return SCIP_OKAY;
6628  }
6629 
6630  assert(consdata->vars != NULL || consdata->nvars == 0);
6631 
6632  /* sorting array after indices of variables, that's only for faster merging */
6633  SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6634  consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6635 
6636  /* knapsack-sorting (decreasing weights) now lost */
6637  consdata->sorted = FALSE;
6638 
6639  v = consdata->nvars - 1;
6640  prev = v - 1;
6641  /* loop backwards through the items: deletion only affects rear items */
6642  while( prev >= 0 )
6643  {
6644  SCIP_VAR* var1;
6645  SCIP_VAR* var2;
6646  SCIP_Bool negated1;
6647  SCIP_Bool negated2;
6648 
6649  negated1 = FALSE;
6650  negated2 = FALSE;
6651 
6652  var1 = consdata->vars[v];
6653  assert(SCIPvarIsBinary(var1));
6654  assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6656  {
6657  var1 = SCIPvarGetNegatedVar(var1);
6658  negated1 = TRUE;
6659  }
6660  assert(var1 != NULL);
6661 
6662  var2 = consdata->vars[prev];
6663  assert(SCIPvarIsBinary(var2));
6664  assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6666  {
6667  var2 = SCIPvarGetNegatedVar(var2);
6668  negated2 = TRUE;
6669  }
6670  assert(var2 != NULL);
6671 
6672  if( var1 == var2 )
6673  {
6674  /* both variables are either active or negated */
6675  if( negated1 == negated2 )
6676  {
6677  /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6678  consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6679  SCIP_CALL( delCoefPos(scip, cons, v) );
6680  }
6681  /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6682  * and delete item of smaller weight
6683  */
6684  else if( consdata->weights[v] == consdata->weights[prev] )
6685  {
6686  /* both variables eliminate themselves: w*x + w*(1-x) == w */
6687  consdata->capacity -= consdata->weights[v];
6688  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6689  SCIP_CALL( delCoefPos(scip, cons, prev) );
6690 
6691  --prev;
6692  }
6693  else if( consdata->weights[v] < consdata->weights[prev] )
6694  {
6695  consdata->capacity -= consdata->weights[v];
6696  consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6697  assert(consdata->weights[prev] > 0);
6698  SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6699  }
6700  else
6701  {
6702  consdata->capacity -= consdata->weights[prev];
6703  consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6704  assert(consdata->weights[v] > 0);
6705  SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6706  /* restore order iff necessary */
6707  if( consdata->nvars != v ) /* otherwise the order still stands */
6708  {
6709  assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6710  /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6711  if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6712  --prev;
6713  else /* we need to let v at the same position*/
6714  {
6715  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6716  /* don't decrease v, the same variable may exist up front */
6717  --prev;
6718  continue;
6719  }
6720  }
6721  }
6722  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6723  }
6724  v = prev;
6725  --prev;
6726  }
6727 
6728  consdata->merged = TRUE;
6729 
6730  /* check infeasibility */
6731  if( consdata->onesweightsum > consdata->capacity )
6732  {
6733  SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6734  *cutoff = TRUE;
6735  return SCIP_OKAY;
6736  }
6737 
6738  return SCIP_OKAY;
6739 }
6740 
6741 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6742  * fixings (dual reductions)
6743  */
6744 static
6746  SCIP* scip, /**< SCIP data structure */
6747  SCIP_CONS* cons, /**< knapsack constraint */
6748  int* nfixedvars, /**< pointer to count number of fixings */
6749  int* ndelconss, /**< pointer to count number of deleted constraints */
6750  SCIP_Bool* deleted /**< pointer to store if the constraint is deleted */
6751  )
6752 {
6753  SCIP_CONSDATA* consdata;
6754  SCIP_VAR** vars;
6755  SCIP_Real* profits;
6756  int* solitems;
6757  int* nonsolitems;
6758  int* items;
6759  SCIP_Real solval;
6760  SCIP_Bool infeasible;
6761  SCIP_Bool tightened;
6762  SCIP_Bool applicable;
6763  int nsolitems;
6764  int nnonsolitems;
6765  int nvars;
6766  int v;
6767 
6768  assert(!SCIPconsIsModifiable(cons));
6769 
6770  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6771  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6772  * added to the problems have the check flag set to FALSE
6773  */
6774  if( !SCIPconsIsChecked(cons) )
6775  return SCIP_OKAY;
6776 
6777  consdata = SCIPconsGetData(cons);
6778  assert(consdata != NULL);
6779 
6780  nvars = consdata->nvars;
6781  vars = consdata->vars;
6782 
6783  SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6784  SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6785  SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6786  SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6787 
6788  applicable = TRUE;
6789 
6790  /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6791  * collect object values which are the profits of the knapsack problem
6792  */
6793  for( v = 0; v < nvars; ++v )
6794  {
6795  SCIP_VAR* var;
6796  SCIP_Bool negated;
6797 
6798  var = vars[v];
6799  assert(var != NULL);
6800 
6801  /* the variable should not be (globally) fixed */
6802  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6803 
6806  {
6807  applicable = FALSE;
6808  break;
6809  }
6810 
6811  negated = FALSE;
6812 
6813  /* get the active variable */
6814  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6815  assert(SCIPvarIsActive(var));
6816 
6817  if( negated )
6818  profits[v] = SCIPvarGetObj(var);
6819  else
6820  profits[v] = -SCIPvarGetObj(var);
6821 
6822  SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6823  SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6824  items[v] = v;
6825  }
6826 
6827  if( applicable )
6828  {
6829  SCIP_Bool success;
6830 
6831  SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6832  SCIPdebugPrintCons(scip, cons, NULL);
6833 
6834  /* solve knapsack problem exactly */
6835  SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6836  items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6837 
6838  if( success )
6839  {
6840  SCIP_VAR* var;
6841 
6842  /* apply solution of the knapsack as dual reductions */
6843  for( v = 0; v < nsolitems; ++v )
6844  {
6845  var = vars[solitems[v]];
6846  assert(var != NULL);
6847 
6848  SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6850  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6851  assert(!infeasible);
6852  assert(tightened);
6853  (*nfixedvars)++;
6854  }
6855 
6856  for( v = 0; v < nnonsolitems; ++v )
6857  {
6858  var = vars[nonsolitems[v]];
6859  assert(var != NULL);
6860 
6861  SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6863  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6864  assert(!infeasible);
6865  assert(tightened);
6866  (*nfixedvars)++;
6867  }
6868 
6869  SCIP_CALL( SCIPdelCons(scip, cons) );
6870  (*ndelconss)++;
6871  (*deleted) = TRUE;
6872  }
6873  }
6874 
6875  SCIPfreeBufferArray(scip, &nonsolitems);
6876  SCIPfreeBufferArray(scip, &solitems);
6877  SCIPfreeBufferArray(scip, &items);
6878  SCIPfreeBufferArray(scip, &profits);
6879 
6880  return SCIP_OKAY;
6881 }
6882 
6883 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6884  * constraint enters the LP by setting the initial and separated flag to FALSE
6885  */
6886 static
6888  SCIP* scip, /**< SCIP data structure */
6889  SCIP_CONS* cons, /**< knapsack constraint */
6890  SCIP_CONSHDLRDATA* conshdlrdata /**< knapsack constraint handler data */
6891  )
6892 {
6893  SCIP_CONSDATA* consdata;
6894  SCIP_VAR** vars;
6895  SCIP_VAR* var;
6896  SCIP_Real offset;
6897  SCIP_Real scale;
6898  SCIP_Real objval;
6899  SCIP_Bool applicable;
6900  SCIP_Bool negated;
6901  int nobjvars;
6902  int nvars;
6903  int v;
6904 
6905  assert(scip != NULL);
6906  assert(cons != NULL);
6907  assert(conshdlrdata != NULL);
6908 
6909  consdata = SCIPconsGetData(cons);
6910  assert(consdata != NULL);
6911 
6912  nvars = consdata->nvars;
6913  nobjvars = SCIPgetNObjVars(scip);
6914 
6915  /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6916  * and/or separated flag is set to FALSE
6917  */
6918  if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6919  return SCIP_OKAY;
6920 
6921  /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6922  * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6923  */
6924  if( nobjvars == 0 )
6925  return SCIP_OKAY;
6926 
6927  vars = consdata->vars;
6928  assert(vars != NULL);
6929 
6930  applicable = TRUE;
6931  offset = 0.0;
6932  scale = 1.0;
6933 
6934  for( v = 0; v < nvars && applicable; ++v )
6935  {
6936  negated = FALSE;
6937  var = vars[v];
6938  assert(var != NULL);
6939 
6940  if( SCIPvarIsNegated(var) )
6941  {
6942  negated = TRUE;
6943  var = SCIPvarGetNegatedVar(var);
6944  assert(var != NULL);
6945  }
6946 
6947  objval = SCIPvarGetObj(var);
6948 
6949  /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6950  if( SCIPisZero(scip, objval) )
6951  applicable = FALSE;
6952  else
6953  {
6954  SCIP_Real weight;
6955 
6956  weight = (SCIP_Real)consdata->weights[v];
6957 
6958  if( negated )
6959  {
6960  if( v == 0 )
6961  {
6962  /* the first variable defines the scale */
6963  scale = weight / -objval;
6964 
6965  offset += weight;
6966  }
6967  else if( SCIPisEQ(scip, -objval * scale, weight) )
6968  offset += weight;
6969  else
6970  applicable = FALSE;
6971  }
6972  else if( v == 0 )
6973  {
6974  /* the first variable define the scale */
6975  scale = weight / objval;
6976  }
6977  else if( !SCIPisEQ(scip, objval * scale, weight) )
6978  applicable = FALSE;
6979  }
6980  }
6981 
6982  if( applicable )
6983  {
6984  if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6985  {
6986  SCIP_Real cutoffbound;
6987 
6988  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6989  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6990  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6991 
6992  cutoffbound = (consdata->capacity - offset) / scale;
6993 
6994  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6995  SCIPconsGetName(cons), cutoffbound);
6996 
6997  /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6998  * still excepted
6999  */
7000  cutoffbound += SCIPcutoffbounddelta(scip);
7001 
7002  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
7003  SCIPconsGetName(cons), cutoffbound);
7004 
7005  if( cutoffbound < SCIPgetCutoffbound(scip) )
7006  {
7007  SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
7008 
7009  SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
7010  }
7011  else
7012  {
7013  /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
7014  * propagation
7015  */
7016  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
7017  SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
7018  }
7019  }
7020  else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
7021  {
7022  SCIP_Real lowerbound;
7023 
7024  /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
7025  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
7026  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
7027 
7028  lowerbound = (consdata->capacity - offset) / scale;
7029 
7030  SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
7031  SCIPconsGetName(cons), lowerbound);
7032 
7033  SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
7034  }
7035  }
7036 
7037  return SCIP_OKAY;
7038 }
7039 
7040 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
7041  * weight of one variable is greater or equal another weight and both variables are in the same cliques */
7042 static
7044  SCIP* scip, /**< SCIP data structure */
7045  SCIP_CONSDATA* consdata, /**< knapsack constraint data */
7046  SCIP_VAR** vars, /**< array for sorted variables */
7047  SCIP_Longint* weights, /**< array for sorted weights */
7048  int* cliquestartposs, /**< starting position array for each clique */
7049  SCIP_Bool usenegatedclique /**< should negated or normal clique partition be used */
7050  )
7052  SCIP_VAR** origvars;
7053  int norigvars;
7054  SCIP_Longint* origweights;
7055  int* cliquepartition;
7056  int ncliques;
7057 
7058  SCIP_VAR*** varpointers;
7059  SCIP_Longint** weightpointers;
7060  int* cliquecount;
7061 
7062  int nextpos;
7063  int c;
7064  int v;
7065 
7066  assert(scip != NULL);
7067  assert(consdata != NULL);
7068  assert(vars != NULL);
7069  assert(weights != NULL);
7070  assert(cliquestartposs != NULL);
7071 
7072  origweights = consdata->weights;
7073  origvars = consdata->vars;
7074  norigvars = consdata->nvars;
7075 
7076  assert(origvars != NULL || norigvars == 0);
7077  assert(origweights != NULL || norigvars == 0);
7078 
7079  if( norigvars == 0 )
7080  return SCIP_OKAY;
7081 
7082  if( usenegatedclique )
7083  {
7084  assert(consdata->negcliquepartitioned);
7085 
7086  cliquepartition = consdata->negcliquepartition;
7087  ncliques = consdata->nnegcliques;
7088  }
7089  else
7090  {
7091  assert(consdata->cliquepartitioned);
7092 
7093  cliquepartition = consdata->cliquepartition;
7094  ncliques = consdata->ncliques;
7095  }
7096 
7097  assert(cliquepartition != NULL);
7098  assert(ncliques > 0);
7099 
7100  /* we first count all clique items and alloc temporary memory for a bucket sort */
7101  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7102  BMSclearMemoryArray(cliquecount, ncliques);
7103 
7104  /* first we count for each clique the number of elements */
7105  for( v = norigvars - 1; v >= 0; --v )
7106  {
7107  assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7108  ++(cliquecount[cliquepartition[v]]);
7109  }
7110 
7111  /*@todo: maybe it is better to put largest cliques up front */
7112 
7113 #ifndef NDEBUG
7114  BMSclearMemoryArray(vars, norigvars);
7115  BMSclearMemoryArray(weights, norigvars);
7116 #endif
7117  SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7118  SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7119 
7120  nextpos = 0;
7121  /* now we initialize all start pointers for each clique, so they will be ordered */
7122  for( c = 0; c < ncliques; ++c )
7123  {
7124  /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7125  * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7126  * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7127  * to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7128  * vars[7]
7129  *
7130  */
7131  varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7132  cliquestartposs[c] = nextpos;
7133  weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7134  assert(cliquecount[c] > 0);
7135  nextpos += cliquecount[c];
7136  assert(nextpos > 0);
7137  }
7138  assert(nextpos == norigvars);
7139  cliquestartposs[c] = nextpos;
7140 
7141  /* now we copy all variable and weights to the right order */
7142  for( v = 0; v < norigvars; ++v )
7143  {
7144  *(varpointers[cliquepartition[v]]) = origvars[v]; /*lint !e613*/
7145  ++(varpointers[cliquepartition[v]]);
7146  *(weightpointers[cliquepartition[v]]) = origweights[v]; /*lint !e613*/
7147  ++(weightpointers[cliquepartition[v]]);
7148  }
7149 #ifndef NDEBUG
7150  for( v = 0; v < norigvars; ++v )
7151  {
7152  assert(vars[v] != NULL);
7153  assert(weights[v] > 0);
7154  }
7155 #endif
7156 
7157  /* free temporary memory */
7158  SCIPfreeBufferArray(scip, &weightpointers);
7159  SCIPfreeBufferArray(scip, &varpointers);
7160  SCIPfreeBufferArray(scip, &cliquecount);
7161 
7162  return SCIP_OKAY;
7163 }
7164 
7165 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7166 static
7168  SCIP* scip, /**< SCIP data structure */
7169  SCIP_CONS* cons, /**< knapsack constraint */
7170  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off, or NULL if this
7171  * information is not needed; in this case, we apply all fixings
7172  * instead of stopping after the first infeasible one */
7173  )
7174 {
7175  SCIP_CONSDATA* consdata;
7176  int v;
7177 
7178  assert(scip != NULL);
7179  assert(cons != NULL);
7180 
7181  consdata = SCIPconsGetData(cons);
7182  assert(consdata != NULL);
7183  assert(consdata->nvars == 0 || consdata->vars != NULL);
7184 
7185  if( cutoff != NULL )
7186  *cutoff = FALSE;
7187 
7188  SCIPdebugMsg(scip, "apply fixings:\n");
7189  SCIPdebugPrintCons(scip, cons, NULL);
7190 
7191  /* check infeasibility */
7192  if ( consdata->onesweightsum > consdata->capacity )
7193  {
7194  SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7195 
7196  if( cutoff != NULL )
7197  *cutoff = TRUE;
7198 
7199  return SCIP_OKAY;
7200  }
7201 
7202  /* all multi-aggregations should be resolved */
7203  consdata->existmultaggr = FALSE;
7204 
7205  v = 0;
7206  while( v < consdata->nvars )
7207  {
7208  SCIP_VAR* var;
7209 
7210  var = consdata->vars[v];
7211  assert(SCIPvarIsBinary(var));
7212 
7213  if( SCIPvarGetLbGlobal(var) > 0.5 )
7214  {
7215  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7216  consdata->capacity -= consdata->weights[v];
7217  SCIP_CALL( delCoefPos(scip, cons, v) );
7218  consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7219  }
7220  else if( SCIPvarGetUbGlobal(var) < 0.5 )
7221  {
7222  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7223  SCIP_CALL( delCoefPos(scip, cons, v) );
7224  }
7225  else
7226  {
7227  SCIP_VAR* repvar;
7228  SCIP_VAR* negvar;
7229  SCIP_VAR* workvar;
7230  SCIP_Longint weight;
7231  SCIP_Bool negated;
7232 
7233  weight = consdata->weights[v];
7234 
7235  /* get binary representative of variable */
7236  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7237  assert(repvar != NULL);
7238 
7239  /* check for multi-aggregation */
7240  if( SCIPvarIsNegated(repvar) )
7241  {
7242  workvar = SCIPvarGetNegatedVar(repvar);
7243  assert(workvar != NULL);
7244  negated = TRUE;
7245  }
7246  else
7247  {
7248  workvar = repvar;
7249  negated = FALSE;
7250  }
7251 
7252  /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7253  * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7254  * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7255  *
7256  * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7257  * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7258  *
7259  * The explanation for the following block:
7260  * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7261  * weight * (a_1*y_1 + ... + a_n*y_n + c).
7262  * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7263  * weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7264  * so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7265  * 2) For all replacement variable we check:
7266  * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7267  * capacity -= weight * a_i caused by the negation of y_i.
7268  * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7269  * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7270  * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7271  * weight in this case.
7272  */
7273  if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7274  {
7275  SCIP_VAR** aggrvars;
7276  SCIP_Real* aggrscalars;
7277  SCIP_Real aggrconst;
7278  int naggrvars;
7279  int i;
7280 
7281  SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7282  naggrvars = SCIPvarGetMultaggrNVars(workvar);
7283  aggrvars = SCIPvarGetMultaggrVars(workvar);
7284  aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7285  aggrconst = SCIPvarGetMultaggrConstant(workvar);
7286  assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7287 
7288  if( !SCIPisIntegral(scip, weight * aggrconst) )
7289  {
7290  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7291  return SCIP_ERROR;
7292  }
7293 
7294  /* if workvar was negated, we have to flip the weight */
7295  if( negated )
7296  weight *= -1;
7297 
7298  for( i = naggrvars - 1; i >= 0; --i )
7299  {
7300  assert(aggrvars != NULL);
7301  assert(aggrscalars != NULL);
7302 
7303  if( !SCIPvarIsBinary(aggrvars[i]) )
7304  {
7305  SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7306  SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]), SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7307  return SCIP_ERROR;
7308  }
7309  if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7310  {
7311  SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7312  return SCIP_ERROR;
7313  }
7314  /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7315  if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7316  {
7317  SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7318  assert(negvar != NULL);
7319  SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7320  consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7321  }
7322  else
7323  {
7324  SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7325  }
7326  }
7327  /* delete old coefficient */
7328  SCIP_CALL( delCoefPos(scip, cons, v) );
7329 
7330  /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7331  if( negated )
7332  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7333  else
7334  consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7335 
7336  if( consdata->capacity < 0 )
7337  {
7338  if( cutoff != NULL )
7339  {
7340  *cutoff = TRUE;
7341  break;
7342  }
7343  }
7344  }
7345  /* check, if the variable should be replaced with the representative */
7346  else if( repvar != var )
7347  {
7348  /* delete old (aggregated) variable */
7349  SCIP_CALL( delCoefPos(scip, cons, v) );
7350 
7351  /* add representative instead */
7352  SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7353  }
7354  else
7355  ++v;
7356  }
7357  }
7358  assert(consdata->onesweightsum == 0);
7359 
7360  SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7361  SCIPdebugPrintCons(scip, cons, NULL);
7362 
7363  /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7364  * clean up the constraint
7365  */
7366  if( cutoff != NULL && !(*cutoff) )
7367  {
7368  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7369  SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7370  SCIPdebugPrintCons(scip, cons, NULL);
7371  }
7372 
7373  return SCIP_OKAY;
7374 }
7375 
7376 
7377 /** propagation method for knapsack constraints */
7378 static
7380  SCIP* scip, /**< SCIP data structure */
7381  SCIP_CONS* cons, /**< knapsack constraint */
7382  SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7383  SCIP_Bool* redundant, /**< pointer to store whether constraint is redundant */
7384  int* nfixedvars, /**< pointer to count number of fixings */
7385  SCIP_Bool usenegatedclique /**< should negated clique information be used */
7386  )
7388  SCIP_CONSDATA* consdata;
7389  SCIP_Bool infeasible;
7390  SCIP_Bool tightened;
7391  SCIP_Longint* secondmaxweights;
7392  SCIP_Longint minweightsum;
7393  SCIP_Longint residualcapacity;
7394 
7395  int nvars;
7396  int i;
7397  int nnegcliques;
7398 
7399  SCIP_VAR** myvars;
7400  SCIP_Longint* myweights;
7401  int* cliquestartposs;
7402  int* cliqueendposs;
7403  SCIP_Longint localminweightsum;
7404  SCIP_Bool foundmax;
7405  int c;
7406 
7407  assert(scip != NULL);
7408  assert(cons != NULL);
7409  assert(cutoff != NULL);
7410  assert(redundant != NULL);
7411  assert(nfixedvars != NULL);
7412 
7413  consdata = SCIPconsGetData(cons);
7414  assert(consdata != NULL);
7415 
7416  *cutoff = FALSE;
7417  *redundant = FALSE;
7418 
7419  SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7420 
7421  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7422  if( !SCIPinRepropagation(scip) )
7423  {
7424  SCIP_CALL( SCIPincConsAge(scip, cons) );
7425  }
7426 
7427 #ifndef NDEBUG
7428  /* assert that only active or negated variables are present */
7429  for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7430  {
7431  assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7432  }
7433 #endif
7434 
7435  usenegatedclique = usenegatedclique && consdata->merged;
7436 
7437  /* init for debugging */
7438  myvars = NULL;
7439  myweights = NULL;
7440  cliquestartposs = NULL;
7441  secondmaxweights = NULL;
7442  minweightsum = 0;
7443  nvars = consdata->nvars;
7444  /* make sure, the items are sorted by non-increasing weight */
7445  sortItems(consdata);
7446 
7447  do
7448  {
7449  localminweightsum = 0;
7450 
7451  /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7452  * a negated clique means, that at most one of the clique variables can be zero
7453  * - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7454  *
7455  * if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7456  * since replacing i with the element of maximal weight leads to infeasibility
7457  */
7458  if( usenegatedclique && nvars > 0 )
7459  {
7460  SCIP_CONSHDLRDATA* conshdlrdata;
7461  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7462  assert(conshdlrdata != NULL);
7463 
7464  /* compute clique partitions */
7465  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7466  nnegcliques = consdata->nnegcliques;
7467 
7468  /* if we have no real negated cliques we can stop here */
7469  if( nnegcliques == nvars )
7470  {
7471  /* run the standard algorithm that does not involve cliques */
7472  usenegatedclique = FALSE;
7473  break;
7474  }
7475 
7476  /* allocate temporary memory and initialize it */
7477  SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7478  SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7479  SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7480  SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7481  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7482  BMSclearMemoryArray(secondmaxweights, nnegcliques);
7483 
7484  /* resort variables to avoid quadratic algorithm later on */
7485  SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7486 
7487  /* save the end positions of the cliques because start positions are moved in the following loop */
7488  for( c = 0; c < nnegcliques; ++c )
7489  {
7490  cliqueendposs[c] = cliquestartposs[c+1] - 1;
7491  assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7492  }
7493 
7494  c = 0;
7495  foundmax = FALSE;
7496  i = 0;
7497 
7498  while( i < nvars )
7499  {
7500  /* ignore variables of the negated clique which are fixed to one since these are counted in
7501  * consdata->onesweightsum
7502  */
7503 
7504  /* if there are only one variable negated cliques left we can stop */
7505  if( nnegcliques - c == nvars - i )
7506  {
7507  minweightsum += localminweightsum;
7508  localminweightsum = 0;
7509  break;
7510  }
7511 
7512  /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7513  * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7514  * other clique variables to one
7515  */
7516  if( cliquestartposs[c] == i )
7517  {
7518  assert(myweights[i] > 0);
7519  ++c;
7520  minweightsum += localminweightsum;
7521  localminweightsum = 0;
7522  foundmax = TRUE;
7523 
7524  if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7525  foundmax = FALSE;
7526 
7527  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7528  {
7529  ++i;
7530  continue;
7531  }
7532  }
7533 
7534  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7535  {
7536  assert(myweights[i] > 0);
7537 
7538  if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7539  {
7540  assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7541 
7542  if( !foundmax )
7543  {
7544  foundmax = TRUE;
7545 
7546  /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7547  cliquestartposs[c - 1] = i;
7548  ++i;
7549 
7550  continue;
7551  }
7552  /* memorize second max weight for each clique */
7553  if( secondmaxweights[c - 1] == 0 )
7554  secondmaxweights[c - 1] = myweights[i];
7555 
7556  localminweightsum += myweights[i];
7557  }
7558  /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7559  else
7560  {
7561  int v;
7562  /* fix all other variables of the negated clique to 1 */
7563  for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7564  {
7565  if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7566  {
7567  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7568  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7569 
7570  if( infeasible )
7571  {
7572  assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7573 
7574  /* analyze the infeasibility if conflict analysis is applicable */
7576  {
7577  /* conflict analysis can only be applied in solving stage */
7578  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7579 
7580  /* initialize the conflict analysis */
7582 
7583  /* add the two variables which are fixed to zero within a negated clique */
7584  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7585  SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7586 
7587  /* start the conflict analysis */
7588  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7589  }
7590  *cutoff = TRUE;
7591  break;
7592  }
7593  assert(tightened);
7594  ++(*nfixedvars);
7595  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7596  }
7597  }
7598 
7599  /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7600  localminweightsum = 0;
7601  /* we can jump to the end of this clique */
7602  i = cliqueendposs[c - 1];
7603 
7604  if( *cutoff )
7605  break;
7606  }
7607  }
7608  ++i;
7609  }
7610  /* add last clique minweightsum */
7611  minweightsum += localminweightsum;
7612 
7613  SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7614  SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7615 
7616  /* check, if weights of fixed variables don't exceeds knapsack capacity */
7617  if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7618  {
7619  SCIP_Longint maxcliqueweight = -1LL;
7620 
7621  /* loop over cliques */
7622  for( c = 0; c < nnegcliques; ++c )
7623  {
7624  SCIP_VAR* maxvar;
7625  SCIP_Bool maxvarfixed;
7626  int endvarposclique;
7627  int startvarposclique;
7628 
7629  assert(myvars != NULL);
7630  assert(nnegcliques == consdata->nnegcliques);
7631  assert(myweights != NULL);
7632  assert(secondmaxweights != NULL);
7633  assert(cliquestartposs != NULL);
7634 
7635  endvarposclique = cliqueendposs[c];
7636  startvarposclique = cliquestartposs[c];
7637 
7638  maxvar = myvars[startvarposclique];
7639 
7640  /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7641  if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7642  continue;
7643 
7644  maxcliqueweight = myweights[startvarposclique];
7645  maxvarfixed = FALSE;
7646  /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7647  * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7648  * exceeds the capacity the maximum weight variable can be fixed to zero.
7649  */
7650  if( consdata->onesweightsum + minweightsum + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7651  {
7652 #ifndef NDEBUG
7653  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7654 #endif
7655  assert(maxcliqueweight >= secondmaxweights[c]);
7656  assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7657 
7658  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7659  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7660  SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7661  assert(consdata->onesweightsum == oldonesweightsum);
7662  assert(!infeasible);
7663  assert(tightened);
7664  (*nfixedvars)++;
7665  maxvarfixed = TRUE;
7666  }
7667  /* the remaining cliques are singletons such that all subsequent variables have a weight that
7668  * fits into the knapsack
7669  */
7670  else if( nnegcliques - c == nvars - startvarposclique )
7671  break;
7672  /* early termination of the remaining loop because no further variable fixings are possible:
7673  *
7674  * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7675  * largest was set to 0) does not suffice to infer additional variable fixings because
7676  *
7677  * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7678  * - their second largest elements are at least as large as the smallest weight of the knapsack
7679  */
7680  else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7681  break;
7682 
7683  /* loop over items with non-maximal weight (omitting the first position) */
7684  for( i = endvarposclique; i > startvarposclique; --i )
7685  {
7686  /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7687  * messed up the clique preprocessing in the previous loop to filter those variables out */
7688  assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7689 
7690  /* only check variables of negated cliques for which no variable is locally fixed */
7691  if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7692  {
7693  assert(maxcliqueweight >= myweights[i]);
7694  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7695 
7696  /* we fix the members of this clique with non-maximal weight in two cases to 1:
7697  *
7698  * the maxvar was already fixed to 0 because it has a huge gain.
7699  *
7700  * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity => xi = 1
7701  * since replacing i with the element of maximal weight leads to infeasibility */
7702  if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity )
7703  {
7704 #ifndef NDEBUG
7705  SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7706 #endif
7707  SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7708  SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7709  assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7710  assert(!infeasible);
7711  assert(tightened);
7712  ++(*nfixedvars);
7713  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7714 
7715  /* update minweightsum because now the variable is fixed to one and its weight is counted by
7716  * consdata->onesweightsum
7717  */
7718  minweightsum -= myweights[i];
7719  assert(minweightsum >= 0);
7720  }
7721  else
7722  break;
7723  }
7724  }
7725 #ifndef NDEBUG
7726  /* in debug mode, we assert that we did not miss possible fixings by the break above */
7727  for( ; i > startvarposclique; --i )
7728  {
7729  SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7730  SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7731 
7732  assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7733  assert(varisfixed || !exceedscapacity);
7734  }
7735 #endif
7736  }
7737  }
7738  SCIPfreeBufferArray(scip, &secondmaxweights);
7739  SCIPfreeBufferArray(scip, &cliqueendposs);
7740  SCIPfreeBufferArray(scip, &cliquestartposs);
7741  SCIPfreeBufferArray(scip, &myweights);
7742  SCIPfreeBufferArray(scip, &myvars);
7743  }
7744 
7745  assert(consdata->negcliquepartitioned || minweightsum == 0);
7746  }
7747  while( FALSE );
7748 
7749  assert(usenegatedclique || minweightsum == 0);
7750  /* check, if weights of fixed variables already exceed knapsack capacity */
7751  if( consdata->capacity < minweightsum + consdata->onesweightsum )
7752  {
7753  SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7754  consdata->onesweightsum, consdata->capacity);
7755 
7756  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7757  *cutoff = TRUE;
7758 
7759  /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7761  {
7762  /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7763  SCIP_Longint weight;
7764 
7765  weight = 0;
7766 
7768 
7769  for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7770  {
7771  if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7772  {
7773  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7774  weight += consdata->weights[i];
7775  }
7776  }
7777 
7778  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7779  }
7780 
7781  return SCIP_OKAY;
7782  }
7783 
7784  /* the algorithm below is a special case of propagation involving negated cliques */
7785  if( !usenegatedclique )
7786  {
7787  assert(consdata->sorted);
7788  residualcapacity = consdata->capacity - consdata->onesweightsum;
7789 
7790  /* fix all variables to zero, that don't fit into the knapsack anymore */
7791  for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7792  {
7793  /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7794  * to zero
7795  */
7796  if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7797  {
7798  if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7799  {
7800  assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7801  SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7802  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7803  SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7804  assert(!infeasible);
7805  assert(tightened);
7806  (*nfixedvars)++;
7807  }
7808  }
7809  }
7810  }
7811 
7812  /* check if the knapsack is now redundant */
7813  if( !SCIPconsIsModifiable(cons) )
7814  {
7815  SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7816 
7817  /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7818  for( i = 0; i < nvars; ++i )
7819  {
7820  if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7821  {
7822  unfixedweightsum += consdata->weights[i];
7823 
7824  /* the weight sum is larger than the capacity, so the constraint is not redundant */
7825  if( unfixedweightsum > consdata->capacity )
7826  return SCIP_OKAY;
7827  }
7828  }
7829  /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7830  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7831  SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7832  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7833  *redundant = TRUE;
7834  }
7835 
7836  return SCIP_OKAY;
7837 }
7838 
7839 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7840  * containing all negated variables of this knapsack constraint
7841  */
7842 static
7844  SCIP* scip, /**< SCIP data structure */
7845  SCIP_CONS* cons, /**< knapsack constraint */
7846  int* ndelconss, /**< pointer to store the amount of deleted constraints */
7847  int* naddconss /**< pointer to count number of added constraints */
7848  )
7849 {
7850  SCIP_CONS* newcons;
7851  SCIP_CONSDATA* consdata;
7852 
7853  assert(scip != NULL);
7854  assert(cons != NULL);
7855  assert(ndelconss != NULL);
7856  assert(naddconss != NULL);
7857 
7858  consdata = SCIPconsGetData(cons);
7859  assert(consdata != NULL);
7860  assert(consdata->nvars > 1);
7861 
7862  /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7863  if( consdata->nvars == 2 )
7864  {
7865  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7866 
7867  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7871  SCIPconsIsStickingAtNode(cons)) );
7872  }
7873  /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7874  * containing all negated variables of the knapsack
7875  */
7876  else
7877  {
7878  SCIP_VAR** consvars;
7879 
7880  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7881 
7882  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7883  SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7884 
7885  SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7889  SCIPconsIsStickingAtNode(cons)) );
7890 
7891  SCIPfreeBufferArray(scip, &consvars);
7892  }
7893 
7894  SCIP_CALL( SCIPaddCons(scip, newcons) );
7895  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7896  ++(*naddconss);
7897 
7898  SCIP_CALL( SCIPdelCons(scip, cons) );
7899  ++(*ndelconss);
7900 
7901  return SCIP_OKAY;
7902 }
7903 
7904 /** delete redundant variables
7905  *
7906  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
7907  *
7908  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7909  * => x4, x5 always fits into the knapsack, so we can delete them
7910  *
7911  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7912  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7913  */
7914 static
7916  SCIP* scip, /**< SCIP data structure */
7917  SCIP_CONS* cons, /**< knapsack constraint */
7918  SCIP_Longint frontsum, /**< sum of front items which fit if we try to take from the first till the last */
7919  int splitpos, /**< split position till when all front items are fitting, splitpos is the
7920  * first which did not fit */
7921  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
7922  int* nchgsides, /**< pointer to store the amount of changed sides */
7923  int* naddconss /**< pointer to count number of added constraints */
7924  )
7925 {
7926  SCIP_CONSHDLRDATA* conshdlrdata;
7927  SCIP_CONSDATA* consdata;
7928  SCIP_VAR** vars;
7929  SCIP_Longint* weights;
7930  SCIP_Longint capacity;
7931  SCIP_Longint gcd;
7932  int nvars;
7933  int w;
7934 
7935  assert(scip != NULL);
7936  assert(cons != NULL);
7937  assert(nchgcoefs != NULL);
7938  assert(nchgsides != NULL);
7939  assert(naddconss != NULL);
7940 
7941  consdata = SCIPconsGetData(cons);
7942  assert(consdata != NULL);
7943  assert(0 < frontsum && frontsum < consdata->weightsum);
7944  assert(0 < splitpos && splitpos < consdata->nvars);
7945 
7946  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7947  assert(conshdlrdata != NULL);
7948 
7949  vars = consdata->vars;
7950  weights = consdata->weights;
7951  nvars = consdata->nvars;
7952  capacity = consdata->capacity;
7953 
7954  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7955  * weight must not be sorted by their index
7956  */
7957 #ifndef NDEBUG
7958  for( w = nvars - 1; w > 0; --w )
7959  assert(weights[w] <= weights[w-1]);
7960 #endif
7961 
7962  /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7963  if( consdata->nvars - 1 == splitpos )
7964  return SCIP_OKAY;
7965 
7966  assert(frontsum + weights[splitpos] > capacity);
7967 
7968  /* detect redundant variables */
7969  if( consdata->weightsum - weights[splitpos] <= capacity )
7970  {
7971  /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7972  * fit
7973  */
7974  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7975 
7976  /* delete items and update capacity */
7977  for( w = nvars - 1; w > splitpos; --w )
7978  {
7979  consdata->capacity -= weights[w];
7980  SCIP_CALL( delCoefPos(scip, cons, w) );
7981  }
7982  assert(w == splitpos);
7983 
7984  ++(*nchgsides);
7985  *nchgcoefs += (nvars - splitpos);
7986 
7987  /* division by greatest common divisor */
7988  gcd = weights[w];
7989  for( ; w >= 0 && gcd > 1; --w )
7990  {
7991  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7992  }
7993 
7994  /* normalize if possible */
7995  if( gcd > 1 )
7996  {
7997  for( w = splitpos; w >= 0; --w )
7998  {
7999  consdataChgWeight(consdata, w, weights[w]/gcd);
8000  }
8001  (*nchgcoefs) += nvars;
8002 
8003  consdata->capacity /= gcd;
8004  ++(*nchgsides);
8005  }
8006 
8007  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8008  * weight must not be sorted by their index
8009  */
8010 #ifndef NDEBUG
8011  for( w = consdata->nvars - 1; w > 0; --w )
8012  assert(weights[w] <= weights[w - 1]);
8013 #endif
8014  }
8015  /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
8016  * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
8017  * splitpos and needs to fit into the knapsack
8018  */
8019  else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
8020  {
8021  int* clqpart;
8022  int nclq;
8023  int len;
8024 
8025  len = nvars - (splitpos + 1);
8026  /* allocate temporary memory */
8027  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
8028 
8029  /* calculate clique partition */
8030  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
8031 
8032  /* check if we found at least one clique */
8033  if( nclq < len )
8034  {
8035  SCIP_Longint maxactduetoclq;
8036  int cliquenum;
8037 
8038  maxactduetoclq = 0;
8039  cliquenum = 0;
8040 
8041  /* calculate maximum activity due to cliques */
8042  for( w = 0; w < len; ++w )
8043  {
8044  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8045  if( clqpart[w] == cliquenum )
8046  {
8047  maxactduetoclq += weights[w + splitpos + 1];
8048  ++cliquenum;
8049  }
8050  }
8051 
8052  /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
8053  * so delete them and create for all clique the corresponding clique constraints and update the capacity
8054  */
8055  if( frontsum + maxactduetoclq <= capacity )
8056  {
8057  SCIP_VAR** clqvars;
8058  int nclqvars;
8059  int c;
8060 
8061  assert(maxactduetoclq < weights[splitpos]);
8062 
8063  SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8064 
8065  /* allocate temporary memory */
8066  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
8067 
8068  for( c = 0; c < nclq; ++c )
8069  {
8070  nclqvars = 0;
8071  for( w = 0; w < len; ++w )
8072  {
8073  if( clqpart[w] == c )
8074  {
8075  clqvars[nclqvars] = vars[w + splitpos + 1];
8076  ++nclqvars;
8077  }
8078  }
8079 
8080  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8081  if( nclqvars > 1 )
8082  {
8083  SCIP_CONS* cliquecons;
8084  char name[SCIP_MAXSTRLEN];
8085 
8086  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8087  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8091  SCIPconsIsStickingAtNode(cons)) );
8092  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8093  SCIPdebugPrintCons(scip, cliquecons, NULL);
8094  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8095  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8096  ++(*naddconss);
8097  }
8098  }
8099 
8100  /* delete items and update capacity */
8101  for( w = nvars - 1; w > splitpos; --w )
8102  {
8103  SCIP_CALL( delCoefPos(scip, cons, w) );
8104  ++(*nchgcoefs);
8105  }
8106  consdata->capacity -= maxactduetoclq;
8107  assert(frontsum <= consdata->capacity);
8108  ++(*nchgsides);
8109 
8110  assert(w == splitpos);
8111 
8112  /* renew weights pointer */
8113  weights = consdata->weights;
8114 
8115  /* division by greatest common divisor */
8116  gcd = weights[w];
8117  for( ; w >= 0 && gcd > 1; --w )
8118  {
8119  gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8120  }
8121 
8122  /* normalize if possible */
8123  if( gcd > 1 )
8124  {
8125  for( w = splitpos; w >= 0; --w )
8126  {
8127  consdataChgWeight(consdata, w, weights[w]/gcd);
8128  }
8129  (*nchgcoefs) += nvars;
8130 
8131  consdata->capacity /= gcd;
8132  ++(*nchgsides);
8133  }
8134 
8135  /* free temporary memory */
8136  SCIPfreeBufferArray(scip, &clqvars);
8137 
8138  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8139  * weight must not be sorted by their index
8140  */
8141 #ifndef NDEBUG
8142  for( w = consdata->nvars - 1; w > 0; --w )
8143  assert(weights[w] <= weights[w - 1]);
8144 #endif
8145  }
8146  }
8147 
8148  /* free temporary memory */
8149  SCIPfreeBufferArray(scip, &clqpart);
8150  }
8151 
8152  return SCIP_OKAY;
8153 }
8154 
8155 /* detect redundant variables which always fits into the knapsack
8156  *
8157  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13 => x4, x5 always fits into the knapsack, so we can delete them
8158  *
8159  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8160  * => x4, x5 always fits into the knapsack, so we can delete them
8161  *
8162  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8163  * => we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8164  */
8165 static
8167  SCIP* scip, /**< SCIP data structure */
8168  SCIP_CONS* cons, /**< knapsack constraint */
8169  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8170  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8171  int* nchgsides, /**< pointer to store the amount of changed sides */
8172  int* naddconss /**< pointer to count number of added constraints */
8173  )
8175  SCIP_CONSHDLRDATA* conshdlrdata;
8176  SCIP_CONSDATA* consdata;
8177  SCIP_VAR** vars;
8178  SCIP_Longint* weights;
8179  SCIP_Longint capacity;
8180  SCIP_Longint sum;
8181  int noldchgcoefs;
8182  int nvars;
8183  int v;
8184  int w;
8185 
8186  assert(scip != NULL);
8187  assert(cons != NULL);
8188  assert(ndelconss != NULL);
8189  assert(nchgcoefs != NULL);
8190  assert(nchgsides != NULL);
8191  assert(naddconss != NULL);
8192 
8193  consdata = SCIPconsGetData(cons);
8194  assert(consdata != NULL);
8195  assert(consdata->nvars >= 2);
8196  assert(consdata->weightsum > consdata->capacity);
8197 
8198  noldchgcoefs = *nchgcoefs;
8199  vars = consdata->vars;
8200  weights = consdata->weights;
8201  nvars = consdata->nvars;
8202  capacity = consdata->capacity;
8203  sum = 0;
8204 
8205  /* search for maximal fitting items */
8206  for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8207  sum += weights[v];
8208 
8209  assert(v < nvars);
8210 
8211  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8212  if( v == nvars - 1 )
8213  {
8214  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8215  assert(SCIPconsIsDeleted(cons));
8216 
8217  return SCIP_OKAY;
8218  }
8219 
8220  if( v < nvars - 1 )
8221  {
8222  /* try to delete variables */
8223  SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8224  assert(consdata->nvars > 1);
8225 
8226  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8227  if( v == consdata->nvars - 1 )
8228  {
8229  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8230  assert(SCIPconsIsDeleted(cons));
8231  }
8232 
8233  return SCIP_OKAY;
8234  }
8235 
8236  /* if we already found some redundant variables, stop here */
8237  if( *nchgcoefs > noldchgcoefs )
8238  return SCIP_OKAY;
8239 
8240  assert(vars == consdata->vars);
8241  assert(weights == consdata->weights);
8242  assert(nvars == consdata->nvars);
8243  assert(capacity == consdata->capacity);
8244 
8245  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8246  assert(conshdlrdata != NULL);
8247  /* calculate clique partition */
8248  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8249 
8250  /* check for real existing cliques */
8251  if( consdata->cliquepartition[v] < v )
8252  {
8253  SCIP_Longint sumfront;
8254  SCIP_Longint maxactduetoclqfront;
8255  int* clqpart;
8256  int cliquenum;
8257 
8258  sumfront = 0;
8259  maxactduetoclqfront = 0;
8260 
8261  clqpart = consdata->cliquepartition;
8262  cliquenum = 0;
8263 
8264  /* calculate maximal activity due to cliques */
8265  for( w = 0; w < nvars; ++w )
8266  {
8267  assert(clqpart[w] >= 0 && clqpart[w] <= w);
8268  if( clqpart[w] == cliquenum )
8269  {
8270  if( maxactduetoclqfront + weights[w] <= capacity )
8271  {
8272  maxactduetoclqfront += weights[w];
8273  ++cliquenum;
8274  }
8275  else
8276  break;
8277  }
8278  sumfront += weights[w];
8279  }
8280  assert(w >= v);
8281 
8282  /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8283  * information
8284  */
8285  if( conshdlrdata->disaggregation && w == nvars )
8286  {
8287  SCIP_VAR** clqvars;
8288  int nclqvars;
8289  int c;
8290  int ncliques;
8291 
8292  assert(maxactduetoclqfront <= capacity);
8293 
8294  SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8295 
8296  ncliques = consdata->ncliques;
8297 
8298  /* allocate temporary memory */
8299  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8300 
8301  for( c = 0; c < ncliques; ++c )
8302  {
8303  nclqvars = 0;
8304  for( w = 0; w < nvars; ++w )
8305  {
8306  if( clqpart[w] == c )
8307  {
8308  clqvars[nclqvars] = vars[w];
8309  ++nclqvars;
8310  }
8311  }
8312 
8313  /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8314  if( nclqvars > 1 )
8315  {
8316  SCIP_CONS* cliquecons;
8317  char name[SCIP_MAXSTRLEN];
8318 
8319  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8320  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8324  SCIPconsIsStickingAtNode(cons)) );
8325  SCIPdebugMsg(scip, " -> adding clique constraint: ");
8326  SCIPdebugPrintCons(scip, cliquecons, NULL);
8327  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8328  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8329  ++(*naddconss);
8330  }
8331  }
8332 
8333  /* delete old constraint */
8334  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8335  ++(*ndelconss);
8336 
8337  SCIPfreeBufferArray(scip, &clqvars);
8338 
8339  return SCIP_OKAY;
8340  }
8341 
8342  if( w > v && w < nvars - 1 )
8343  {
8344  /* try to delete variables */
8345  SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8346  }
8347  }
8348 
8349  return SCIP_OKAY;
8350 }
8351 
8352 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8353 static
8354 void normalizeWeights(
8355  SCIP_CONS* cons, /**< knapsack constraint */
8356  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
8357  int* nchgsides /**< pointer to count number of side changes */
8358  )
8359 {
8360  SCIP_CONSDATA* consdata;
8361  SCIP_Longint gcd;
8362  int i;
8363 
8364  assert(nchgcoefs != NULL);
8365  assert(nchgsides != NULL);
8366  assert(!SCIPconsIsModifiable(cons));
8367 
8368  consdata = SCIPconsGetData(cons);
8369  assert(consdata != NULL);
8370  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8371  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8372  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8373  assert(consdata->nvars >= 1);
8374 
8375  /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8376  sortItems(consdata);
8377 
8378  gcd = consdata->weights[consdata->nvars-1];
8379  for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8380  {
8381  assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8382  assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8383 
8384  gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8385  }
8386 
8387  if( gcd >= 2 )
8388  {
8389  SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8390 
8391  for( i = 0; i < consdata->nvars; ++i )
8392  {
8393  consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8394  }
8395  consdata->capacity /= gcd;
8396  (*nchgcoefs) += consdata->nvars;
8397  (*nchgsides)++;
8398 
8399  /* weight should still be sorted, because the reduction preserves this */
8400 #ifndef NDEBUG
8401  for( i = consdata->nvars - 1; i > 0; --i )
8402  assert(consdata->weights[i] <= consdata->weights[i - 1]);
8403 #endif
8404  consdata->sorted = TRUE;
8405  }
8406 }
8407 
8408 /** dual weights tightening for knapsack constraints
8409  *
8410  * 1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8411  * b) check if all but the smallest weight fit into the knapsack, then we can upgrade this constraint to a logicor
8412  * constraint
8413  *
8414  * 2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8415  * these are a minimal cover, then might reduce the weights and the capacity, e.g.
8416  *
8417  * +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8418  *
8419  * 3. use the duality between a^Tx <= capacity <=> a^T~x >= weightsum - capacity to tighten weights, e.g.
8420  *
8421  * 11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27 <=> 11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8422  *
8423  * the above constraint can be changed to 8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8424  *
8425  * 16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26 <=> 16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8426  */
8427 static
8429  SCIP* scip, /**< SCIP data structure */
8430  SCIP_CONS* cons, /**< knapsack constraint */
8431  int* ndelconss, /**< pointer to store the amount of deleted constraints */
8432  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
8433  int* nchgsides, /**< pointer to store the amount of changed sides */
8434  int* naddconss /**< pointer to count number of added constraints */
8435  )
8437  SCIP_CONSDATA* consdata;
8438  SCIP_Longint* weights;
8439  SCIP_Longint dualcapacity;
8440  SCIP_Longint reductionsum;
8441  SCIP_Longint capacity;
8442  SCIP_Longint exceedsum;
8443  int oldnchgcoefs;
8444  int nvars;
8445  int vbig;
8446  int v;
8447  int w;
8448 #ifndef NDEBUG
8449  int oldnchgsides;
8450 #endif
8451 
8452  assert(scip != NULL);
8453  assert(cons != NULL);
8454  assert(ndelconss != NULL);
8455  assert(nchgcoefs != NULL);
8456  assert(nchgsides != NULL);
8457  assert(naddconss != NULL);
8458 
8459 #ifndef NDEBUG
8460  oldnchgsides = *nchgsides;
8461 #endif
8462 
8463  consdata = SCIPconsGetData(cons);
8464  assert(consdata != NULL);
8465  assert(consdata->weightsum > consdata->capacity);
8466  assert(consdata->nvars >= 2);
8467  assert(consdata->sorted);
8468 
8469  /* constraint should be merged */
8470  assert(consdata->merged);
8471 
8472  nvars = consdata->nvars;
8473  weights = consdata->weights;
8474  capacity = consdata->capacity;
8475 
8476  oldnchgcoefs = *nchgcoefs;
8477 
8478  /* case 1. */
8479  if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8480  {
8481  SCIP_CONS* newcons;
8482 
8483  /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8484  *
8485  * e.g. 5x1 + 4x2 + 3x3 <= 5 <=> x1 + x2 + x3 <= 1
8486  */
8487  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8488 
8489  SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8493  SCIPconsIsStickingAtNode(cons)) );
8494 
8495  SCIP_CALL( SCIPaddCons(scip, newcons) );
8496  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8497  ++(*naddconss);
8498 
8499  SCIP_CALL( SCIPdelCons(scip, cons) );
8500  ++(*ndelconss);
8501 
8502  return SCIP_OKAY;
8503  }
8504 
8505  /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8506  if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8507  {
8508  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8509  assert(SCIPconsIsDeleted(cons));
8510 
8511  return SCIP_OKAY;
8512  }
8513 
8514  /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8515  /* @todo might be changed/removed when improving the coeffcients tightening */
8516  if( consdata->weightsum - capacity > weights[0] + weights[1] )
8517  return SCIP_OKAY;
8518 
8519  /* case 2. */
8520 
8521  v = 0;
8522 
8523  /* @todo generalize the following algorithm for several parts of the knapsack
8524  *
8525  * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8526  * variables each combination is a minimal cover, some examples
8527  *
8528  * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8529  * <=> ~x1 + ~x2 + ~x3 + ~x4 + ~x5 >= 2
8530  * <=> x1 + x2 + x3 + x4 + x5 <= 3
8531  *
8532  * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219 <=> 3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8533  *
8534  */
8535 
8536  /* determine big weights that fit only by itself */
8537  while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8538  ++v;
8539 
8540  vbig = v;
8541  assert(vbig < nvars - 1);
8542  exceedsum = 0;
8543 
8544  /* determine the amount needed to exceed the capacity */
8545  while( v < nvars && exceedsum <= capacity )
8546  {
8547  exceedsum += weights[v];
8548  ++v;
8549  }
8550 
8551  /* if we exceeded the capacity we might reduce the weights */
8552  if( exceedsum > capacity )
8553  {
8554  assert(vbig > 0 || v < nvars);
8555 
8556  /* all small weights were needed to exceed the capacity */
8557  if( v == nvars )
8558  {
8559  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8560  assert(newweight > 0);
8561 
8562  /* reduce big weights */
8563  for( v = 0; v < vbig; ++v )
8564  {
8565  if( weights[v] > newweight )
8566  {
8567  consdataChgWeight(consdata, v, newweight);
8568  ++(*nchgcoefs);
8569  }
8570  }
8571 
8572  /* reduce small weights */
8573  for( ; v < nvars; ++v )
8574  {
8575  if( weights[v] > 1 )
8576  {
8577  consdataChgWeight(consdata, v, 1LL);
8578  ++(*nchgcoefs);
8579  }
8580  }
8581 
8582  consdata->capacity = newweight;
8583 
8584  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8585  * weight must not be sorted by their index
8586  */
8587 #ifndef NDEBUG
8588  for( v = nvars - 1; v > 0; --v )
8589  assert(weights[v] <= weights[v-1]);
8590 #endif
8591 
8592  return SCIP_OKAY;
8593  }
8594  /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8595  * small weights
8596  */
8597  else
8598  {
8599  SCIP_Longint exceedsumback = 0;
8600  int nexceed = v - vbig;
8601 
8602  assert(nexceed > 1);
8603 
8604  /* determine weightsum of the same amount as before but of the smallest weight */
8605  for( w = nvars - 1; w >= nvars - nexceed; --w )
8606  exceedsumback += weights[w];
8607 
8608  assert(w >= 0);
8609 
8610  /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8611  * combinations of all small weights
8612  */
8613  if( exceedsumback > capacity )
8614  {
8615  SCIP_Longint newweight = nexceed - 1;
8616 
8617  /* taking out the smallest element needs to fit */
8618  assert(exceedsumback - weights[nvars - 1] <= capacity);
8619 
8620  /* reduce big weights */
8621  for( v = 0; v < vbig; ++v )
8622  {
8623  if( weights[v] > newweight )
8624  {
8625  consdataChgWeight(consdata, v, newweight);
8626  ++(*nchgcoefs);
8627  }
8628  }
8629 
8630  /* reduce small weights */
8631  for( ; v < nvars; ++v )
8632  {
8633  if( weights[v] > 1 )
8634  {
8635  consdataChgWeight(consdata, v, 1LL);
8636  ++(*nchgcoefs);
8637  }
8638  }
8639 
8640  consdata->capacity = newweight;
8641 
8642  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8643  * weight must not be sorted by their index
8644  */
8645 #ifndef NDEBUG
8646  for( v = nvars - 1; v > 0; --v )
8647  assert(weights[v] <= weights[v-1]);
8648 #endif
8649  return SCIP_OKAY;
8650  }
8651  }
8652  }
8653  else
8654  {
8655  /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8656  * not happen here
8657  */
8658  assert(vbig > 0 && vbig < nvars);
8659 
8660  /* either choose a big coefficients or all other variables
8661  *
8662  * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8663  *
8664  * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8665  * constraint to
8666  *
8667  * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8668  */
8669 
8670  if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8671  {
8672  SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8673 #ifndef NDEBUG
8674  SCIP_Longint resweightsum = consdata->weightsum;
8675 
8676  for( v = 0; v < vbig; ++v )
8677  resweightsum -= weights[v];
8678 
8679  assert(exceedsum == resweightsum);
8680 #endif
8681  assert(newweight > 0);
8682 
8683  /* reduce big weights */
8684  for( v = 0; v < vbig; ++v )
8685  {
8686  if( weights[v] > newweight )
8687  {
8688  consdataChgWeight(consdata, v, newweight);
8689  ++(*nchgcoefs);
8690  }
8691  }
8692 
8693  /* reduce small weights */
8694  for( ; v < nvars; ++v )
8695  {
8696  if( weights[v] > 1 )
8697  {
8698  consdataChgWeight(consdata, v, 1LL);
8699  ++(*nchgcoefs);
8700  }
8701  }
8702 
8703  consdata->capacity = newweight;
8704 
8705  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8706  * weight must not be sorted by their index
8707  */
8708 #ifndef NDEBUG
8709  for( v = nvars - 1; v > 0; --v )
8710  assert(weights[v] <= weights[v-1]);
8711 #endif
8712  return SCIP_OKAY;
8713  }
8714  }
8715 
8716  /* case 3. */
8717 
8718  dualcapacity = consdata->weightsum - capacity;
8719  reductionsum = 0;
8720  v = 0;
8721 
8722  /* reduce big weights
8723  *
8724  * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32 <=> 11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8725  * <=> 10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8726  * <=> x0 + x1 + x2 + x3 <= 3
8727  */
8728  while( weights[v] > dualcapacity )
8729  {
8730  reductionsum += (weights[v] - dualcapacity);
8731  consdataChgWeight(consdata, v, dualcapacity);
8732  ++v;
8733  assert(v < nvars);
8734  }
8735  (*nchgcoefs) += v;
8736 
8737  /* skip weights equal to the dualcapacity, because we cannot change them */
8738  while( v < nvars && weights[v] == dualcapacity )
8739  ++v;
8740 
8741  /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8742  * after a possible removal of the last, redundant item
8743  *
8744  * e.g. 10x1 + 10x2 + 10x3 <= 20 <=> 10~x1 + 10~x2 + 10~x3 >= 10 <=> ~x1 + ~x2 + ~x3 >= 1
8745  */
8746  if( v >= nvars - 1 )
8747  {
8748  /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8749  if( v == nvars - 1 )
8750  {
8751  SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8752  }
8753  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8754  assert(SCIPconsIsDeleted(cons));
8755 
8756  return SCIP_OKAY;
8757  }
8758  else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8759  {
8760  /* @todo generalize the following algorithm for more than two variables */
8761 
8762  if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8763  {
8764  /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8765  * coefficients) of all or two variables of the rest
8766  *
8767  * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8768  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 >= 2
8769  * <=> 2x1 + 2x2 + x3 + x4 <= 4
8770  *
8771  * 3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12 <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8772  * <=> 2~x1 + 2~x2 + ~x3 + ~x4 + ~x5 + ~x6 + ~x7 >= 2
8773  * <=> 2 x1 + 2 x2 + x3 + x4 + x5 + x6 + x7 <= 7
8774  *
8775  */
8776  if( v > 0 && weights[nvars - 2] > 1 )
8777  {
8778  int ncoefchg = 0;
8779 
8780  /* reduce all bigger weights */
8781  for( w = 0; w < v; ++w )
8782  {
8783  if( weights[w] > 2 )
8784  {
8785  consdataChgWeight(consdata, w, 2LL);
8786  ++ncoefchg;
8787  }
8788  else
8789  {
8790  assert(weights[0] == 2);
8791  assert(weights[v - 1] == 2);
8792  break;
8793  }
8794  }
8795 
8796  /* reduce all smaller weights */
8797  for( w = v; w < nvars; ++w )
8798  {
8799  if( weights[w] > 1 )
8800  {
8801  consdataChgWeight(consdata, w, 1LL);
8802  ++ncoefchg;
8803  }
8804  }
8805  assert(ncoefchg > 0);
8806 
8807  (*nchgcoefs) += ncoefchg;
8808 
8809  /* correct the capacity */
8810  consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8811  assert(consdata->capacity > 0);
8812  assert(weights[0] <= consdata->capacity);
8813  assert(consdata->weightsum > consdata->capacity);
8814  /* reset the reductionsum */
8815  reductionsum = 0;
8816  }
8817  else if( v == 0 )
8818  {
8819  assert(weights[nvars - 2] == 1);
8820  }
8821  }
8822  else
8823  {
8824  SCIP_Longint minweight = weights[nvars - 1];
8825  SCIP_Longint newweight = dualcapacity - minweight;
8826  SCIP_Longint restsumweights = 0;
8827  SCIP_Longint sumcoef;
8828  SCIP_Bool sumcoefcase = FALSE;
8829  int startv = v;
8830  int end;
8831  int k;
8832 
8833  assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8834 
8835  /* reduce big weights of pairs that exceed the dualcapacity
8836  *
8837  * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27 <=> 9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8838  * <=> 9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8839  * <=> 9x1 + 9x2 + 5x3 + 4x4 + 4x5 + 4x6 <= 27
8840  */
8841  while( weights[v] > newweight )
8842  {
8843  reductionsum += (weights[v] - newweight);
8844  consdataChgWeight(consdata, v, newweight);
8845  ++v;
8846  assert(v < nvars);
8847  }
8848  (*nchgcoefs) += (v - startv);
8849 
8850  /* skip equal weights */
8851  while( weights[v] == newweight )
8852  ++v;
8853 
8854  if( v > 0 )
8855  {
8856  for( w = v; w < nvars; ++w )
8857  restsumweights += weights[w];
8858  }
8859  else
8860  restsumweights = consdata->weightsum;
8861 
8862  if( restsumweights < dualcapacity )
8863  {
8864  /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8865  *
8866  * +61x1 + 61x2 + 61x3 + 61x4 + 61x5 + 61x6 + 35x7 + 10x8 <= 350 <=>
8867  * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8868  */
8869  if( startv == v )
8870  {
8871  /* remove redundant variables */
8872  for( w = nvars - 1; w >= v; --w )
8873  {
8874  SCIP_CALL( delCoefPos(scip, cons, v) );
8875  ++(*nchgcoefs);
8876  }
8877 
8878 #ifndef NDEBUG
8879  /* each coefficients should exceed the dualcapacity by itself */
8880  for( ; w >= 0; --w )
8881  assert(weights[w] == dualcapacity);
8882 #endif
8883  /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8884  * upgrade this constraint
8885  */
8886  SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8887  assert(SCIPconsIsDeleted(cons));
8888 
8889  return SCIP_OKAY;
8890  }
8891 
8892  /* special case where we have three different coefficient types
8893  *
8894  * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29 <=> 9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8895  * <=> 9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8896  * <=> 3~x1 + 3~x2 + 2~x3 + 2~x4 + ~x5 + ~x6 >= 3
8897  * <=> 3x1 + 3x2 + 2x3 + 2x4 + x5 + x6 <= 9
8898  */
8899  if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8900  {
8901  SCIP_Longint newcap;
8902 
8903  /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8904  for( w = nvars - 1; w >= v; --w )
8905  {
8906  if( weights[w] > 1 )
8907  {
8908  consdataChgWeight(consdata, w, 1LL);
8909  ++(*nchgcoefs);
8910  }
8911  }
8912 
8913  /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8914  * dualcapacity
8915  */
8916  newweight = (SCIP_Longint)nvars - v;
8917  assert(newweight > 1);
8918  for( ; w >= startv; --w )
8919  {
8920  if( weights[w] > newweight )
8921  {
8922  consdataChgWeight(consdata, w, newweight);
8923  ++(*nchgcoefs);
8924  }
8925  else
8926  assert(weights[w] == newweight);
8927  }
8928 
8929  /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8930  ++newweight;
8931  assert(newweight > 2);
8932  for( ; w >= 0; --w )
8933  {
8934  if( weights[w] > newweight )
8935  {
8936  consdataChgWeight(consdata, w, newweight);
8937  ++(*nchgcoefs);
8938  }
8939  else
8940  assert(weights[w] == newweight);
8941  }
8942 
8943  /* update the capacity */
8944  newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1) + ((SCIP_Longint)nvars - v);
8945  if( consdata->capacity > newcap )
8946  {
8947  consdata->capacity = newcap;
8948  ++(*nchgsides);
8949  }
8950  else
8951  assert(consdata->capacity == newcap);
8952  }
8953  assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8954 
8955  /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8956  assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8957 
8958  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8959  * weight must not be sorted by their index
8960  */
8961 #ifndef NDEBUG
8962  for( w = nvars - 1; w > 0; --w )
8963  assert(weights[w] <= weights[w - 1]);
8964 #endif
8965  return SCIP_OKAY;
8966  }
8967 
8968  /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8969  end = nvars - 2;
8970  while( end >= 0 && weights[end] == weights[end + 1] )
8971  {
8972  assert(end >= v);
8973  --end;
8974  }
8975 
8976  if( v >= end )
8977  goto TERMINATE;
8978 
8979  end = nvars - 2;
8980 
8981  /* can we stop early, another special reduction case might exist */
8982  if( 2 * weights[end] > dualcapacity )
8983  {
8984  restsumweights = 0;
8985 
8986  /* determine capacity of the small items */
8987  for( w = end + 1; w < nvars; ++w )
8988  restsumweights += weights[w];
8989 
8990  if( restsumweights * 2 <= dualcapacity )
8991  {
8992  /* check for further posssible reductions in the middle */
8993  while( v < end && restsumweights + weights[v] >= dualcapacity )
8994  ++v;
8995 
8996  if( v >= end )
8997  goto TERMINATE;
8998 
8999  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9000  if( (dualcapacity & 1) == 0 )
9001  {
9002  newweight = dualcapacity / 2;
9003 
9004  /* set all middle coefficients */
9005  for( ; v <= end; ++v )
9006  {
9007  if( weights[v] > newweight )
9008  {
9009  reductionsum += (weights[v] - newweight);
9010  consdataChgWeight(consdata, v, newweight);
9011  ++(*nchgcoefs);
9012  }
9013  }
9014  }
9015  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9016  * other coefficients by 2
9017  */
9018  else
9019  {
9020  /* correct the reductionsum */
9021  reductionsum *= 2;
9022 
9023  /* multiply big coefficients by 2 */
9024  for( w = 0; w < v; ++w )
9025  {
9026  consdataChgWeight(consdata, w, weights[w] * 2);
9027  }
9028 
9029  newweight = dualcapacity;
9030  /* set all middle coefficients */
9031  for( ; v <= end; ++v )
9032  {
9033  reductionsum += (2 * weights[v] - newweight);
9034  consdataChgWeight(consdata, v, newweight);
9035  }
9036 
9037  /* multiply small coefficients by 2 */
9038  for( w = end + 1; w < nvars; ++w )
9039  {
9040  consdataChgWeight(consdata, w, weights[w] * 2);
9041  }
9042  (*nchgcoefs) += nvars;
9043 
9044  dualcapacity *= 2;
9045  consdata->capacity *= 2;
9046  ++(*nchgsides);
9047  }
9048  }
9049 
9050  goto TERMINATE;
9051  }
9052 
9053  /* further reductions using the next possible coefficient sum
9054  *
9055  * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19 <=> 9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
9056  * <=> 9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
9057  * <=> 9x1 + 8x2 + 6x3 + 3x4 + x5 <= 18
9058  */
9059  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
9060  for( k = 0; k < 4; ++k )
9061  {
9062  /* determine next minimal coefficient sum */
9063  switch( k )
9064  {
9065  case 0:
9066  sumcoef = weights[nvars - 1] + weights[nvars - 2];
9067  break;
9068  case 1:
9069  assert(nvars >= 3);
9070  sumcoef = weights[nvars - 1] + weights[nvars - 3];
9071  break;
9072  case 2:
9073  assert(nvars >= 4);
9074  if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9075  {
9076  sumcoefcase = TRUE;
9077  sumcoef = weights[nvars - 1] + weights[nvars - 4];
9078  }
9079  else
9080  {
9081  sumcoefcase = FALSE;
9082  sumcoef = weights[nvars - 2] + weights[nvars - 3];
9083  }
9084  break;
9085  case 3:
9086  assert(nvars >= 5);
9087  if( sumcoefcase )
9088  {
9089  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9090  }
9091  else
9092  {
9093  sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9094  }
9095  break;
9096  default:
9097  return SCIP_ERROR;
9098  }
9099 
9100  /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9101  minweight = weights[end];
9102  while( minweight <= sumcoef )
9103  {
9104  newweight = dualcapacity - minweight;
9105  startv = v;
9106  assert(v < nvars);
9107 
9108  /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9109  /* shrink big coefficients */
9110  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9111  {
9112  reductionsum += (weights[v] - newweight);
9113  consdataChgWeight(consdata, v, newweight);
9114  ++v;
9115  assert(v < nvars);
9116  }
9117  (*nchgcoefs) += (v - startv);
9118 
9119  /* skip unchangable weights */
9120  while( weights[v] + minweight == dualcapacity )
9121  {
9122  assert(v < nvars);
9123  ++v;
9124  }
9125 
9126  --end;
9127  /* skip same end weights */
9128  while( end >= 0 && weights[end] == weights[end + 1] )
9129  --end;
9130 
9131  if( v >= end )
9132  goto TERMINATE;
9133 
9134  minweight = weights[end];
9135  }
9136 
9137  if( v >= end )
9138  goto TERMINATE;
9139 
9140  /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9141  if( sumcoef < minweight )
9142  {
9143  minweight = sumcoef;
9144  newweight = dualcapacity - minweight;
9145  startv = v;
9146  assert(v < nvars);
9147 
9148  /* shrink big coefficients */
9149  while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9150  {
9151  reductionsum += (weights[v] - newweight);
9152  consdataChgWeight(consdata, v, newweight);
9153  ++v;
9154  assert(v < nvars);
9155  }
9156  (*nchgcoefs) += (v - startv);
9157 
9158  /* skip unchangable weights */
9159  while( weights[v] + minweight == dualcapacity )
9160  {
9161  assert(v < nvars);
9162  ++v;
9163  }
9164  }
9165 
9166  if( v >= end )
9167  goto TERMINATE;
9168 
9169  /* can we stop early, another special reduction case might exist */
9170  if( 2 * weights[end] > dualcapacity )
9171  {
9172  restsumweights = 0;
9173 
9174  /* determine capacity of the small items */
9175  for( w = end + 1; w < nvars; ++w )
9176  restsumweights += weights[w];
9177 
9178  if( restsumweights * 2 <= dualcapacity )
9179  {
9180  /* check for further posssible reductions in the middle */
9181  while( v < end && restsumweights + weights[v] >= dualcapacity )
9182  ++v;
9183 
9184  if( v >= end )
9185  goto TERMINATE;
9186 
9187  /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9188  if( (dualcapacity & 1) == 0 )
9189  {
9190  newweight = dualcapacity / 2;
9191 
9192  /* set all middle coefficients */
9193  for( ; v <= end; ++v )
9194  {
9195  if( weights[v] > newweight )
9196  {
9197  reductionsum += (weights[v] - newweight);
9198  consdataChgWeight(consdata, v, newweight);
9199  ++(*nchgcoefs);
9200  }
9201  }
9202  }
9203  /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9204  * other coefficients by 2
9205  */
9206  else
9207  {
9208  /* correct the reductionsum */
9209  reductionsum *= 2;
9210 
9211  /* multiply big coefficients by 2 */
9212  for( w = 0; w < v; ++w )
9213  {
9214  consdataChgWeight(consdata, w, weights[w] * 2);
9215  }
9216 
9217  newweight = dualcapacity;
9218  /* set all middle coefficients */
9219  for( ; v <= end; ++v )
9220  {
9221  reductionsum += (2 * weights[v] - newweight);
9222  consdataChgWeight(consdata, v, newweight);
9223  }
9224 
9225  /* multiply small coefficients by 2 */
9226  for( w = end + 1; w < nvars; ++w )
9227  {
9228  consdataChgWeight(consdata, w, weights[w] * 2);
9229  }
9230  (*nchgcoefs) += nvars;
9231 
9232  dualcapacity *= 2;
9233  consdata->capacity *= 2;
9234  ++(*nchgsides);
9235  }
9236  }
9237 
9238  goto TERMINATE;
9239  }
9240 
9241  /* cannot tighten any further */
9242  if( 2 * sumcoef > dualcapacity )
9243  goto TERMINATE;
9244  }
9245  }
9246  }
9247 
9248  TERMINATE:
9249  /* correct capacity */
9250  if( reductionsum > 0 )
9251  {
9252  assert(v > 0);
9253 
9254  consdata->capacity -= reductionsum;
9255  ++(*nchgsides);
9256 
9257  assert(consdata->weightsum - dualcapacity == consdata->capacity);
9258  }
9259  assert(weights[0] <= consdata->capacity);
9260 
9261  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9262  * weight must not be sorted by their index
9263  */
9264 #ifndef NDEBUG
9265  for( w = nvars - 1; w > 0; --w )
9266  assert(weights[w] <= weights[w - 1]);
9267 #endif
9268 
9269  if( oldnchgcoefs < *nchgcoefs )
9270  {
9271  assert(!SCIPconsIsDeleted(cons));
9272 
9273  /* it might be that we can divide the weights by their greatest common divisor */
9274  normalizeWeights(cons, nchgcoefs, nchgsides);
9275  }
9276  else
9277  {
9278  assert(oldnchgcoefs == *nchgcoefs);
9279  assert(oldnchgsides == *nchgsides);
9280  }
9281 
9282  return SCIP_OKAY;
9283 }
9284 
9285 
9286 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9287 static
9289  SCIP* scip, /**< SCIP data structure */
9290  SCIP_CONS* cons, /**< knapsack constraint */
9291  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9292  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9293  int* nchgcoefs /**< pointer to store the amount of changed coefficients */
9294  )
9295 {
9296  SCIP_VAR** vars;
9297  SCIP_CONSDATA* consdata;
9298  SCIP_Longint* weights;
9299  SCIP_Longint capacity;
9300  SCIP_Bool infeasible;
9301  SCIP_Bool fixed;
9302  int nvars;
9303  int v;
9304 
9305  assert(scip != NULL);
9306  assert(cons != NULL);
9307  assert(nfixedvars != NULL);
9308  assert(ndelconss != NULL);
9309  assert(nchgcoefs != NULL);
9310 
9311  consdata = SCIPconsGetData(cons);
9312  assert(consdata != NULL);
9313 
9314  nvars = consdata->nvars;
9315 
9316  /* no variables left, then delete constraint */
9317  if( nvars == 0 )
9318  {
9319  assert(consdata->capacity >= 0);
9320 
9321  SCIP_CALL( SCIPdelCons(scip, cons) );
9322  ++(*ndelconss);
9323 
9324  return SCIP_OKAY;
9325  }
9326 
9327  /* sort items */
9328  sortItems(consdata);
9329 
9330  vars = consdata->vars;
9331  weights = consdata->weights;
9332  capacity = consdata->capacity;
9333  v = 0;
9334 
9335  /* check for weights bigger than the capacity */
9336  while( v < nvars && weights[v] > capacity )
9337  {
9338  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9339  assert(!infeasible);
9340 
9341  if( fixed )
9342  ++(*nfixedvars);
9343 
9344  ++v;
9345  }
9346 
9347  /* if we fixed at least one variable we need to delete them from the constraint */
9348  if( v > 0 )
9349  {
9350  if( v == nvars )
9351  {
9352  SCIP_CALL( SCIPdelCons(scip, cons) );
9353  ++(*ndelconss);
9354 
9355  return SCIP_OKAY;
9356  }
9357 
9358  /* delete all position from back to front */
9359  for( --v; v >= 0; --v )
9360  {
9361  SCIP_CALL( delCoefPos(scip, cons, v) );
9362  ++(*nchgcoefs);
9363  }
9364 
9365  /* sort items again because of deletion */
9366  sortItems(consdata);
9367  assert(vars == consdata->vars);
9368  assert(weights == consdata->weights);
9369  }
9370  assert(consdata->sorted);
9371  assert(weights[0] <= capacity);
9372 
9373  if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9374  {
9375  SCIP_CALL( SCIPdelCons(scip, cons) );
9376  ++(*ndelconss);
9377  }
9378 
9379  return SCIP_OKAY;
9380 }
9381 
9382 
9383 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9384  *
9385  * 1. use the duality between a^Tx <= capacity <=> -a^T~x <= capacity - weightsum to tighten weights, e.g.
9386  *
9387  * 11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25 <=> -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9388  *
9389  * the above constraint can be changed to
9390  *
9391  * -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12 <=> 8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9392  *
9393  * 2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9394  *
9395  * 7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9396  *
9397  * 3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9398  * constraint further, e.g.
9399  *
9400  * 9x1 + 6x2 + 6x3 + 5x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => 3x1 + 2x2 + 2x3 + 2x4 <= 4 => 4x1 + 2x2 + 2x3 + 2x4 <= 4
9401  * => 2x1 + x2 + x3 + x4 <= 2
9402  * 9x1 + 6x2 + 6x3 + 7x4 <= 13 => 9x1 + 6x2 + 6x3 + 6x4 <= 12 => see above
9403  */
9404 static
9406  SCIP* scip, /**< SCIP data structure */
9407  SCIP_CONS* cons, /**< knapsack constraint */
9408  int* nfixedvars, /**< pointer to store the amount of fixed variables */
9409  int* ndelconss, /**< pointer to store the amount of deleted constraints */
9410  int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
9411  int* nchgsides, /**< pointer to store the amount of changed sides */
9412  int* naddconss, /**< pointer to count number of added constraints */
9413  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9414  )
9415 {
9416  SCIP_VAR** vars;
9417  SCIP_CONSDATA* consdata;
9418  SCIP_Longint* weights;
9419  SCIP_Longint restweight;
9420  SCIP_Longint newweight;
9421  SCIP_Longint weight;
9422  SCIP_Longint oldgcd;
9423  SCIP_Longint rest;
9424  SCIP_Longint gcd;
9425  int oldnchgcoefs;
9426  int oldnchgsides;
9427  int candpos;
9428  int candpos2;
9429  int offsetv;
9430  int nvars;
9431  int v;
9432 
9433  assert(scip != NULL);
9434  assert(cons != NULL);
9435  assert(nfixedvars != NULL);
9436  assert(ndelconss != NULL);
9437  assert(nchgcoefs != NULL);
9438  assert(nchgsides != NULL);
9439  assert(naddconss != NULL);
9440  assert(cutoff != NULL);
9441  assert(!SCIPconsIsModifiable(cons));
9442 
9443  consdata = SCIPconsGetData(cons);
9444  assert( consdata != NULL );
9445 
9446  *cutoff = FALSE;
9447 
9448  /* remove double enties and also combinations of active and negated variables */
9449  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9450  assert(consdata->merged);
9451  if( *cutoff )
9452  return SCIP_OKAY;
9453 
9454  assert(consdata->capacity >= 0);
9455 
9456  /* fix variables with big coefficients and remove redundant constraints, sort weights */
9457  SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9458 
9459  if( SCIPconsIsDeleted(cons) )
9460  return SCIP_OKAY;
9461 
9462  if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9463  {
9464  /* 1. dual weights tightening */
9465  SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9466 
9467  if( SCIPconsIsDeleted(cons) )
9468  return SCIP_OKAY;
9469  /* 2. delete redundant variables */
9470  SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9471 
9472  if( SCIPconsIsDeleted(cons) )
9473  return SCIP_OKAY;
9474  }
9475 
9476  weights = consdata->weights;
9477  nvars = consdata->nvars;
9478 
9479 #ifndef NDEBUG
9480  /* constraint might not be sorted, but the weights are already sorted */
9481  for( v = nvars - 1; v > 0; --v )
9482  assert(weights[v] <= weights[v-1]);
9483 #endif
9484 
9485  /* determine greatest common divisor */
9486  gcd = weights[nvars - 1];
9487  for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9488  {
9489  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9490  }
9491 
9492  /* divide the constraint by their greatest common divisor */
9493  if( gcd >= 2 )
9494  {
9495  for( v = nvars - 1; v >= 0; --v )
9496  {
9497  consdataChgWeight(consdata, v, weights[v]/gcd);
9498  }
9499  (*nchgcoefs) += nvars;
9500 
9501  consdata->capacity /= gcd;
9502  (*nchgsides)++;
9503  }
9504  assert(consdata->nvars == nvars);
9505 
9506  /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9507  * must not be sorted by their index
9508  */
9509 #ifndef NDEBUG
9510  for( v = nvars - 1; v > 0; --v )
9511  assert(weights[v] <= weights[v-1]);
9512 #endif
9513 
9514  /* 3. start gcd procedure for all variables */
9515  do
9516  {
9517  SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9518  SCIPdebug( oldnchgsides = *nchgsides; )
9519 
9520  vars = consdata->vars;
9521  weights = consdata->weights;
9522  nvars = consdata->nvars;
9523 
9524  /* stop if we have two coefficients which are one in absolute value */
9525  if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9526  return SCIP_OKAY;
9527 
9528  v = 0;
9529  /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9530  * gcd
9531  */
9532  while( weights[v] == consdata->capacity )
9533  {
9534  ++v;
9535  assert(v < nvars);
9536  }
9537 
9538  /* all but one variable are as big as the capacity, this is handled elsewhere */
9539  if( v == nvars - 1 )
9540  return SCIP_OKAY;
9541 
9542  offsetv = v;
9543 
9544  gcd = -1;
9545  candpos = -1;
9546  candpos2 = -1;
9547 
9548  /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9549  * change the coefficient
9550  */
9551  for( v = nvars - 1; v >= offsetv; --v )
9552  {
9553  weight = weights[v];
9554  assert(weight >= 1);
9555 
9556  oldgcd = gcd;
9557 
9558  if( gcd == -1 )
9559  {
9560  gcd = weights[v];
9561  assert(gcd >= 1);
9562  }
9563  else
9564  {
9565  /* calculate greatest common divisor for all variables */
9566  gcd = SCIPcalcGreComDiv(gcd, weight);
9567  }
9568 
9569  /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9570  * can terminate
9571  */
9572  if( gcd == 1 )
9573  {
9574  /* found candidate */
9575  if( candpos == -1 )
9576  {
9577  gcd = oldgcd;
9578  candpos = v;
9579 
9580  /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9581  if( v == nvars - 2 )
9582  candpos2 = v + 1;
9583  }
9584  /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9585  else
9586  {
9587  if( candpos == v + 1 && candpos2 == v + 2 )
9588  {
9589  assert(candpos2 == nvars - 1);
9590 
9591  /* take new candidates */
9592  candpos = candpos2;
9593 
9594  /* recalculate gcd from scratch */
9595  gcd = weights[v+1];
9596  assert(gcd >= 1);
9597 
9598  /* calculate greatest common divisor for variables */
9599  gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9600  if( gcd == 1 )
9601  return SCIP_OKAY;
9602  }
9603  else
9604  /* cannot determine a possible coefficient for reduction */
9605  return SCIP_OKAY;
9606  }
9607  }
9608  }
9609  assert(gcd >= 2);
9610 
9611  /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9612  * further
9613  */
9614  assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9615 
9616  /* determine the remainder of the capacity and the gcd */
9617  rest = consdata->capacity % gcd;
9618  assert(rest >= 0);
9619  assert(rest < gcd);
9620 
9621  if( candpos == -1 )
9622  {
9623  /* we assume that the constraint was normalized */
9624  assert(rest > 0);
9625 
9626  /* replace old with new capacity */
9627  consdata->capacity -= rest;
9628  ++(*nchgsides);
9629 
9630  /* replace old big coefficients with new capacity */
9631  for( v = 0; v < offsetv; ++v )
9632  {
9633  consdataChgWeight(consdata, v, consdata->capacity);
9634  }
9635 
9636  *nchgcoefs += offsetv;
9637  goto CONTINUE;
9638  }
9639 
9640  /* determine the remainder of the coefficient candidate and the gcd */
9641  restweight = weights[candpos] % gcd;
9642  assert(restweight >= 1);
9643  assert(restweight < gcd);
9644 
9645  /* calculate new coefficient */
9646  if( restweight > rest )
9647  newweight = weights[candpos] - restweight + gcd;
9648  else
9649  newweight = weights[candpos] - restweight;
9650 
9651  assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9652 
9653  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);
9654 
9655  /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9656  * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9657  */
9658  if( newweight == 0 && offsetv > 0 )
9659  return SCIP_OKAY;
9660 
9661  if( rest > 0 )
9662  {
9663  /* replace old with new capacity */
9664  consdata->capacity -= rest;
9665  ++(*nchgsides);
9666 
9667  /* replace old big coefficients with new capacity */
9668  for( v = 0; v < offsetv; ++v )
9669  {
9670  consdataChgWeight(consdata, v, consdata->capacity);
9671  }
9672 
9673  *nchgcoefs += offsetv;
9674  }
9675 
9676  if( newweight == 0 )
9677  {
9678  /* delete redundant coefficient */
9679  SCIP_CALL( delCoefPos(scip, cons, candpos) );
9680  assert(consdata->nvars == nvars - 1);
9681  --nvars;
9682  }
9683  else
9684  {
9685  /* replace old with new coefficient */
9686  consdataChgWeight(consdata, candpos, newweight);
9687  }
9688  ++(*nchgcoefs);
9689 
9690  assert(consdata->vars == vars);
9691  assert(consdata->nvars == nvars);
9692  assert(consdata->weights == weights);
9693 
9694  CONTINUE:
9695  /* now constraint can be normalized, dividing it by the gcd */
9696  for( v = nvars - 1; v >= 0; --v )
9697  {
9698  consdataChgWeight(consdata, v, weights[v]/gcd);
9699  }
9700  (*nchgcoefs) += nvars;
9701 
9702  consdata->capacity /= gcd;
9703  ++(*nchgsides);
9704 
9705  SCIPdebugPrintCons(scip, cons, NULL);
9706 
9707  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));
9708  }
9709  while( nvars >= 2 );
9710 
9711  return SCIP_OKAY;
9712 }
9713 
9714 
9715 /** inserts an element into the list of binary zero implications */
9716 static
9718  SCIP* scip, /**< SCIP data structure */
9719  int** liftcands, /**< array of the lifting candidates */
9720  int* nliftcands, /**< number of lifting candidates */
9721  int** firstidxs, /**< array of first zeroitems indices */
9722  SCIP_Longint** zeroweightsums, /**< array of sums of weights of the implied-to-zero items */
9723  int** zeroitems, /**< pointer to zero items array */
9724  int** nextidxs, /**< pointer to array of next zeroitems indeces */
9725  int* zeroitemssize, /**< pointer to size of zero items array */
9726  int* nzeroitems, /**< pointer to length of zero items array */
9727  int probindex, /**< problem index of variable y in implication y == v -> x == 0 */
9728  SCIP_Bool value, /**< value v of variable y in implication */
9729  int knapsackidx, /**< index of variable x in knapsack */
9730  SCIP_Longint knapsackweight, /**< weight of variable x in knapsack */
9731  SCIP_Bool* memlimitreached /**< pointer to store whether the memory limit was reached */
9732  )
9733 {
9734  int nzeros;
9735 
9736  assert(liftcands != NULL);
9737  assert(liftcands[value] != NULL);
9738  assert(nliftcands != NULL);
9739  assert(firstidxs != NULL);
9740  assert(firstidxs[value] != NULL);
9741  assert(zeroweightsums != NULL);
9742  assert(zeroweightsums[value] != NULL);
9743  assert(zeroitems != NULL);
9744  assert(nextidxs != NULL);
9745  assert(zeroitemssize != NULL);
9746  assert(nzeroitems != NULL);
9747  assert(*nzeroitems <= *zeroitemssize);
9748  assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9749  assert(memlimitreached != NULL);
9750 
9751  nzeros = *nzeroitems;
9752 
9753  /* allocate enough memory */
9754  if( nzeros == *zeroitemssize )
9755  {
9756  /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9757  * this can be too huge - abort on memory limit
9758  */
9759  if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9760  {
9761  SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9762  *zeroitemssize);
9763  *memlimitreached = TRUE;
9764  return SCIP_OKAY;
9765  }
9766  *zeroitemssize *= 2;
9767  *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9768  SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9769  SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9770  }
9771  assert(nzeros < *zeroitemssize);
9772 
9773  if( *memlimitreached )
9774  *memlimitreached = FALSE;
9775 
9776  /* insert element */
9777  (*zeroitems)[nzeros] = knapsackidx;
9778  (*nextidxs)[nzeros] = firstidxs[value][probindex];
9779  if( firstidxs[value][probindex] == 0 )
9780  {
9781  liftcands[value][nliftcands[value]] = probindex;
9782  ++nliftcands[value];
9783  }
9784  firstidxs[value][probindex] = nzeros;
9785  ++(*nzeroitems);
9786  zeroweightsums[value][probindex] += knapsackweight;
9787 
9788  return SCIP_OKAY;
9789 }
9790 
9791 #define MAX_CLIQUELENGTH 50
9792 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9793  * (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9794  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9795  * if cliqueweightsum(xi == v) < capacity:
9796  * - fixing variable xi to v would make the knapsack constraint redundant
9797  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9798  * redundancy effect:
9799  * wi' := capacity - cliqueweightsum(xi == v)
9800  * this rule can also be applied to binary variables not in the knapsack!
9801  */
9802 static
9804  SCIP* scip, /**< SCIP data structure */
9805  SCIP_CONS* cons, /**< knapsack constraint */
9806  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9807  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
9808  )
9809 {
9810  SCIP_CONSDATA* consdata;
9811  SCIP_VAR** binvars;
9812  int nbinvars;
9813  int* liftcands[2]; /* binary variables that have at least one entry in zeroitems */
9814  int* firstidxs[2]; /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9815  SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9816  int* zeroitems; /* item number in knapsack that is implied to zero */
9817  int* nextidxs; /* next index in zeroitems for the same binary variable, or zero for end of list */
9818  int zeroitemssize;
9819  int nzeroitems;
9820  SCIP_Bool* zeroiteminserted[2];
9821  SCIP_Bool memlimitreached;
9822  int nliftcands[2];
9823  SCIP_Bool* cliqueused;
9824  SCIP_Bool* itemremoved;
9825  SCIP_Longint maxcliqueweightsum;
9826  SCIP_VAR** addvars;
9827  SCIP_Longint* addweights;
9828  SCIP_Longint addweightsum;
9829  int nvars;
9830  int cliquenum;
9831  int naddvars;
9832  int val;
9833  int i;
9834 
9835  int* tmpindices;
9836  SCIP_Bool* tmpboolindices;
9837  int* tmpindices2;
9838  SCIP_Bool* tmpboolindices2;
9839  int* tmpindices3;
9840  SCIP_Bool* tmpboolindices3;
9841  int tmp;
9842  int tmp2;
9843  int tmp3;
9844  SCIP_CONSHDLR* conshdlr;
9845  SCIP_CONSHDLRDATA* conshdlrdata;
9846 
9847  assert(nchgcoefs != NULL);
9848  assert(!SCIPconsIsModifiable(cons));
9849 
9850  consdata = SCIPconsGetData(cons);
9851  assert(consdata != NULL);
9852  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9853  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9854  assert(consdata->nvars > 0);
9855  assert(consdata->merged);
9856 
9857  nvars = consdata->nvars;
9858 
9859  /* check if the knapsack has too many items/cliques for applying this costly method */
9860  if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9861  return SCIP_OKAY;
9862 
9863  /* sort items, s.t. the heaviest one is in the first position */
9864  sortItems(consdata);
9865 
9866  if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9867  return SCIP_OKAY;
9868 
9869  /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9870  nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9871  assert(nbinvars > 0);
9872  binvars = SCIPgetVars(scip);
9873 
9874  /* get conshdlrdata to use cleared memory */
9875  conshdlr = SCIPconsGetHdlr(cons);
9876  assert(conshdlr != NULL);
9877  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9878  assert(conshdlrdata != NULL);
9879 
9880  /* allocate temporary memory for the list of implied to zero variables */
9881  zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9882  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9883  SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9884 
9885  assert(conshdlrdata->ints1size > 0);
9886  assert(conshdlrdata->ints2size > 0);
9887  assert(conshdlrdata->longints1size > 0);
9888  assert(conshdlrdata->longints2size > 0);
9889 
9890  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9891  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9892  * transform all integers into their binary representation then it maybe happens
9893  */
9894  if( conshdlrdata->ints1size < nbinvars )
9895  {
9896  int oldsize = conshdlrdata->ints1size;
9897 
9898  conshdlrdata->ints1size = nbinvars;
9899  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9900  BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9901  }
9902  if( conshdlrdata->ints2size < nbinvars )
9903  {
9904  int oldsize = conshdlrdata->ints2size;
9905 
9906  conshdlrdata->ints2size = nbinvars;
9907  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9908  BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9909  }
9910  if( conshdlrdata->longints1size < nbinvars )
9911  {
9912  int oldsize = conshdlrdata->longints1size;
9913 
9914  conshdlrdata->longints1size = nbinvars;
9915  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9916  BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9917  }
9918  if( conshdlrdata->longints2size < nbinvars )
9919  {
9920  int oldsize = conshdlrdata->longints2size;
9921 
9922  conshdlrdata->longints2size = nbinvars;
9923  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9924  BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9925  }
9926 
9927  firstidxs[0] = conshdlrdata->ints1;
9928  firstidxs[1] = conshdlrdata->ints2;
9929  zeroweightsums[0] = conshdlrdata->longints1;
9930  zeroweightsums[1] = conshdlrdata->longints2;
9931 
9932  /* check for cleared arrays, all entries are zero */
9933 #ifndef NDEBUG
9934  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9935  {
9936  assert(firstidxs[0][tmp] == 0);
9937  assert(firstidxs[1][tmp] == 0);
9938  assert(zeroweightsums[0][tmp] == 0);
9939  assert(zeroweightsums[1][tmp] == 0);
9940  }
9941 #endif
9942 
9943  SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9944  SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9945 
9946  zeroitems[0] = -1; /* dummy element */
9947  nextidxs[0] = -1;
9948  nzeroitems = 1;
9949  nliftcands[0] = 0;
9950  nliftcands[1] = 0;
9951 
9952  assert(conshdlrdata->bools1size > 0);
9953  assert(conshdlrdata->bools2size > 0);
9954 
9955  /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9956  * than binary + integer variables existed at the presolving initialization method, but for example if you would
9957  * transform all integers into their binary representation then it maybe happens
9958  */
9959  if( conshdlrdata->bools1size < nbinvars )
9960  {
9961  int oldsize = conshdlrdata->bools1size;
9962 
9963  conshdlrdata->bools1size = nbinvars;
9964  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9965  BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9966  }
9967  if( conshdlrdata->bools2size < nbinvars )
9968  {
9969  int oldsize = conshdlrdata->bools2size;
9970 
9971  conshdlrdata->bools2size = nbinvars;
9972  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9973  BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9974  }
9975 
9976  zeroiteminserted[0] = conshdlrdata->bools1;
9977  zeroiteminserted[1] = conshdlrdata->bools2;
9978 
9979  /* check for cleared arrays, all entries are zero */
9980 #ifndef NDEBUG
9981  for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9982  {
9983  assert(zeroiteminserted[0][tmp] == 0);
9984  assert(zeroiteminserted[1][tmp] == 0);
9985  }
9986 #endif
9987 
9988  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9989  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9990  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9991  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9992  SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9993  SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9994 
9995  tmp2 = 0;
9996  tmp3 = 0;
9997 
9998  memlimitreached = FALSE;
9999  for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
10000  {
10001  SCIP_CLIQUE** cliques;
10002  SCIP_VAR* var;
10003  SCIP_Longint weight;
10004  SCIP_Bool value;
10005  int varprobindex;
10006  int ncliques;
10007  int j;
10008 
10009  tmp = 0;
10010 
10011  /* get corresponding active problem variable */
10012  var = consdata->vars[i];
10013  weight = consdata->weights[i];
10014  value = TRUE;
10015  SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
10016  varprobindex = SCIPvarGetProbindex(var);
10017  assert(0 <= varprobindex && varprobindex < nbinvars);
10018 
10019  /* update the zeroweightsum */
10020  zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
10021  tmpboolindices3[tmp3] = !value;
10022  tmpindices3[tmp3] = varprobindex;
10023  ++tmp3;
10024 
10025  /* initialize the arrays of inserted zero items */
10026  /* first add the implications (~x == 1 -> x == 0) */
10027  {
10028  SCIP_Bool implvalue;
10029  int probindex;
10030 
10031  probindex = SCIPvarGetProbindex(var);
10032  assert(0 <= probindex && probindex < nbinvars);
10033 
10034  implvalue = !value;
10035 
10036  /* insert the item into the list of the implied variable/value */
10037  assert( !zeroiteminserted[implvalue][probindex] );
10038 
10039  if( firstidxs[implvalue][probindex] == 0 )
10040  {
10041  tmpboolindices2[tmp2] = implvalue;
10042  tmpindices2[tmp2] = probindex;
10043  ++tmp2;
10044  }
10045  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10046  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10047  &memlimitreached) );
10048  zeroiteminserted[implvalue][probindex] = TRUE;
10049  tmpboolindices[tmp] = implvalue;
10050  tmpindices[tmp] = probindex;
10051  ++tmp;
10052  }
10053 
10054  /* get the cliques where the knapsack item is member of with value 1 */
10055  ncliques = SCIPvarGetNCliques(var, value);
10056  cliques = SCIPvarGetCliques(var, value);
10057  for( j = 0; j < ncliques && !memlimitreached; ++j )
10058  {
10059  SCIP_VAR** cliquevars;
10060  SCIP_Bool* cliquevalues;
10061  int ncliquevars;
10062  int k;
10063 
10064  ncliquevars = SCIPcliqueGetNVars(cliques[j]);
10065 
10066  /* discard big cliques */
10067  if( ncliquevars > MAX_CLIQUELENGTH )
10068  continue;
10069 
10070  cliquevars = SCIPcliqueGetVars(cliques[j]);
10071  cliquevalues = SCIPcliqueGetValues(cliques[j]);
10072 
10073  for( k = ncliquevars - 1; k >= 0; --k )
10074  {
10075  SCIP_Bool implvalue;
10076  int probindex;
10077 
10078  if( var == cliquevars[k] )
10079  continue;
10080 
10081  probindex = SCIPvarGetProbindex(cliquevars[k]);
10082  if( probindex == -1 )
10083  continue;
10084 
10085  assert(0 <= probindex && probindex < nbinvars);
10086  implvalue = cliquevalues[k];
10087 
10088  /* insert the item into the list of the clique variable/value */
10089  if( !zeroiteminserted[implvalue][probindex] )
10090  {
10091  if( firstidxs[implvalue][probindex] == 0 )
10092  {
10093  tmpboolindices2[tmp2] = implvalue;
10094  tmpindices2[tmp2] = probindex;
10095  ++tmp2;
10096  }
10097 
10098  SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10099  &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10100  &memlimitreached) );
10101  zeroiteminserted[implvalue][probindex] = TRUE;
10102  tmpboolindices[tmp] = implvalue;
10103  tmpindices[tmp] = probindex;
10104  ++tmp;
10105 
10106  if( memlimitreached )
10107  break;
10108  }
10109  }
10110  }
10111  /* clear zeroiteminserted */
10112  for( --tmp; tmp >= 0; --tmp)
10113  zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10114  }
10115  SCIPfreeBufferArray(scip, &tmpboolindices);
10116 
10117  /* calculate the clique partition and the maximal sum of weights using the clique information */
10118  assert(consdata->sorted);
10119  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10120 
10121  assert(conshdlrdata->bools3size > 0);
10122 
10123  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10124  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10125  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10126  */
10127  if( conshdlrdata->bools3size < consdata->nvars )
10128  {
10129  int oldsize = conshdlrdata->bools3size;
10130 
10131  conshdlrdata->bools3size = consdata->nvars;;
10132  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10133  BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10134  }
10135 
10136  cliqueused = conshdlrdata->bools3;
10137 
10138  /* check for cleared array, all entries are zero */
10139 #ifndef NDEBUG
10140  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10141  assert(cliqueused[tmp] == 0);
10142 #endif
10143 
10144  maxcliqueweightsum = 0;
10145  tmp = 0;
10146 
10147  /* calculates maximal weight of cliques */
10148  for( i = 0; i < consdata->nvars; ++i )
10149  {
10150  cliquenum = consdata->cliquepartition[i];
10151  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10152 
10153  if( !cliqueused[cliquenum] )
10154  {
10155  maxcliqueweightsum += consdata->weights[i];
10156  cliqueused[cliquenum] = TRUE;
10157  tmpindices[tmp] = cliquenum;
10158  ++tmp;
10159  }
10160  }
10161  /* clear cliqueused */
10162  for( --tmp; tmp >= 0; --tmp)
10163  cliqueused[tmp] = FALSE;
10164 
10165  assert(conshdlrdata->bools4size > 0);
10166 
10167  /* next if condition should normally not be true, because it means that presolving has created more binary variables
10168  * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10169  * method, but for example if you would transform all integers into their binary representation then it maybe happens
10170  */
10171  if( conshdlrdata->bools4size < consdata->nvars )
10172  {
10173  int oldsize = conshdlrdata->bools4size;
10174 
10175  conshdlrdata->bools4size = consdata->nvars;
10176  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10177  BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10178  }
10179 
10180  itemremoved = conshdlrdata->bools4;
10181 
10182  /* check for cleared array, all entries are zero */
10183 #ifndef NDEBUG
10184  for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10185  assert(itemremoved[tmp] == 0);
10186 #endif
10187 
10188  /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10189  * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10190  * included in subsequent cliqueweightsum calculations)
10191  */
10192  SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10193  SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10194  naddvars = 0;
10195  addweightsum = 0;
10196  for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10197  {
10198  for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10199  {
10200  SCIP_Longint cliqueweightsum;
10201  int probindex;
10202  int idx;
10203  int j;
10204 
10205  tmp = 0;
10206 
10207  probindex = liftcands[val][i];
10208  assert(0 <= probindex && probindex < nbinvars);
10209 
10210  /* ignore empty zero lists and variables that cannot be lifted anyways */
10211  if( firstidxs[val][probindex] == 0
10212  || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10213  continue;
10214 
10215  /* mark the items that are implied to zero by setting the current variable to the current value */
10216  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10217  {
10218  assert(0 < idx && idx < nzeroitems);
10219  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10220  itemremoved[zeroitems[idx]] = TRUE;
10221  }
10222 
10223  /* calculate the residual cliqueweight sum */
10224  cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10225  for( j = 0; j < consdata->nvars; ++j )
10226  {
10227  cliquenum = consdata->cliquepartition[j];
10228  assert(0 <= cliquenum && cliquenum < consdata->nvars);
10229  if( !itemremoved[j] )
10230  {
10231  if( !cliqueused[cliquenum] )
10232  {
10233  cliqueweightsum += consdata->weights[j];
10234  cliqueused[cliquenum] = TRUE;
10235  tmpindices[tmp] = cliquenum;
10236  ++tmp;
10237  }
10238 
10239  if( cliqueweightsum >= consdata->capacity )
10240  break;
10241  }
10242  }
10243 
10244  /* check if the weight of the variable/value can be increased */
10245  if( cliqueweightsum < consdata->capacity )
10246  {
10247  SCIP_VAR* var;
10248  SCIP_Longint weight;
10249 
10250  /* insert the variable (with value TRUE) in the list of additional items */
10251  assert(naddvars < 2*nbinvars);
10252  var = binvars[probindex];
10253  if( val == FALSE )
10254  {
10255  SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10256  }
10257  weight = consdata->capacity - cliqueweightsum;
10258  addvars[naddvars] = var;
10259  addweights[naddvars] = weight;
10260  addweightsum += weight;
10261  naddvars++;
10262 
10263  SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10264  SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10265  }
10266 
10267  /* clear itemremoved */
10268  for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10269  {
10270  assert(0 < idx && idx < nzeroitems);
10271  assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10272  itemremoved[zeroitems[idx]] = FALSE;
10273  }
10274  /* clear cliqueused */
10275  for( --tmp; tmp >= 0; --tmp)
10276  cliqueused[tmpindices[tmp]] = FALSE;
10277  }
10278  }
10279 
10280  /* clear part of zeroweightsums */
10281  for( --tmp3; tmp3 >= 0; --tmp3)
10282  zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10283 
10284  /* clear rest of zeroweightsums and firstidxs */
10285  for( --tmp2; tmp2 >= 0; --tmp2)
10286  {
10287  zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10288  firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10289  }
10290 
10291  /* add all additional item weights */
10292  for( i = 0; i < naddvars; ++i )
10293  {
10294  SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10295  }
10296  *nchgcoefs += naddvars;
10297 
10298  if( naddvars > 0 )
10299  {
10300  /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10301  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10302  }
10303 
10304  /* free temporary memory */
10305  SCIPfreeBufferArray(scip, &addweights);
10306  SCIPfreeBufferArray(scip, &addvars);
10307  SCIPfreeBufferArray(scip, &tmpindices);
10308  SCIPfreeBufferArray(scip, &tmpindices2);
10309  SCIPfreeBufferArray(scip, &tmpindices3);
10310  SCIPfreeBufferArray(scip, &tmpboolindices2);
10311  SCIPfreeBufferArray(scip, &tmpboolindices3);
10312  SCIPfreeBufferArray(scip, &nextidxs);
10313  SCIPfreeBufferArray(scip, &zeroitems);
10314  SCIPfreeBufferArray(scip, &liftcands[1]);
10315  SCIPfreeBufferArray(scip, &liftcands[0]);
10316 
10317  return SCIP_OKAY;
10318 }
10319 
10320 /** tightens item weights and capacity in presolving:
10321  * given a knapsack sum(wi*xi) <= capacity
10322  * (1) let weightsum := sum(wi)
10323  * if weightsum - wi < capacity:
10324  * - not using item i would make the knapsack constraint redundant
10325  * - wi and capacity can be changed to have the same redundancy effect and the same results for
10326  * fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10327  * - change coefficients:
10328  * wi' := weightsum - capacity
10329  * capacity' := capacity - (wi - wi')
10330  * (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10331  * - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10332  * weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10333  * MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10334  * can be multiple times the same weight, this can be improved
10335  * - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10336  * weight, to capacity - lastmininmalweightsum, e.g. :
10337  * 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10338  * -> minimal weightsums: 5, 5, 10, 10
10339  * -> 15 + 5 > 19 => increase 15 to 19 - 0 = 19
10340  * -> 10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10341  * 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10342  * (3) let W(C) be the maximal weight of clique C,
10343  * cliqueweightsum := sum(W(C))
10344  * if cliqueweightsum - W(C) < capacity:
10345  * - not using any item of C would make the knapsack constraint redundant
10346  * - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10347  * fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10348  * - change coefficients:
10349  * delta := capacity - (cliqueweightsum - W(C))
10350  * wi' := max(wi - delta, 0)
10351  * capacity' := capacity - delta
10352  * This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10353  * introduce infeasible solutions.
10354  * (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10355  * let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10356  * if cliqueweightsum(xi == v) < capacity:
10357  * - fixing variable xi to v would make the knapsack constraint redundant
10358  * - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10359  * redundancy effect:
10360  * wi' := capacity - cliqueweightsum(xi == v)
10361  * This rule can also be applied to binary variables not in the knapsack!
10362  * (5) if min{w} + wi > capacity:
10363  * - using item i would force to fix other items to zero
10364  * - wi can be increased to the capacity
10365  */
10366 static
10368  SCIP* scip, /**< SCIP data structure */
10369  SCIP_CONS* cons, /**< knapsack constraint */
10370  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
10371  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10372  int* nchgsides, /**< pointer to count number of side changes */
10373  int* naddconss, /**< pointer to count number of added constraints */
10374  int* ndelconss, /**< pointer to count number of deleted constraints */
10375  SCIP_Bool* cutoff /**< pointer to store whether the node can be cut off */
10376  )
10377 {
10378  SCIP_CONSHDLRDATA* conshdlrdata;
10379  SCIP_CONSDATA* consdata;
10380  SCIP_Longint* weights;
10381  SCIP_Longint sumcoef;
10382  SCIP_Longint capacity;
10383  SCIP_Longint newweight;
10384  SCIP_Longint maxweight;
10385  SCIP_Longint minweight;
10386  SCIP_Bool sumcoefcase = FALSE;
10387  int startpos;
10388  int backpos;
10389  int nvars;
10390  int pos;
10391  int k;
10392  int i;
10393 
10394  assert(nchgcoefs != NULL);
10395  assert(nchgsides != NULL);
10396  assert(!SCIPconsIsModifiable(cons));
10397 
10398  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10399  assert(conshdlrdata != NULL);
10400 
10401  consdata = SCIPconsGetData(cons);
10402  assert(consdata != NULL);
10403  assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10404  assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10405  assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10406  assert(consdata->nvars > 0);
10407 
10408  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10409  if( *cutoff )
10410  return SCIP_OKAY;
10411 
10412  /* apply rule (1) */
10413  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10414  {
10415  do
10416  {
10417  assert(consdata->merged);
10418 
10419  /* sort items, s.t. the heaviest one is in the first position */
10420  sortItems(consdata);
10421 
10422  for( i = 0; i < consdata->nvars; ++i )
10423  {
10424  SCIP_Longint weight;
10425 
10426  weight = consdata->weights[i];
10427  if( consdata->weightsum - weight < consdata->capacity )
10428  {
10429  newweight = consdata->weightsum - consdata->capacity;
10430  consdataChgWeight(consdata, i, newweight);
10431  consdata->capacity -= (weight - newweight);
10432  (*nchgcoefs)++;
10433  (*nchgsides)++;
10434  assert(!consdata->sorted);
10435  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",
10436  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10437  consdata->capacity + (weight-newweight), consdata->capacity);
10438  }
10439  else
10440  break;
10441  }
10442  }
10443  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10444  }
10445 
10446  /* check for redundancy */
10447  if( consdata->weightsum <= consdata->capacity )
10448  return SCIP_OKAY;
10449 
10450  pos = 0;
10451  while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10452  ++pos;
10453 
10454  sumcoef = 0;
10455  weights = consdata->weights;
10456  nvars = consdata->nvars;
10457  capacity = consdata->capacity;
10458 
10459  if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10460  pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10461  {
10462  /* further reductions using the next possible coefficient sum
10463  *
10464  * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19 <=> 19x1 + 19x2 + 14x3 + 5x4 + 5x5 <= 19
10465  */
10466  /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10467  for( k = 0; k < 4; ++k )
10468  {
10469  newweight = capacity - sumcoef;
10470 
10471  /* determine next minimal coefficient sum */
10472  switch( k )
10473  {
10474  case 0:
10475  sumcoef = weights[nvars - 1];
10476  backpos = nvars - 1;
10477  break;
10478  case 1:
10479  sumcoef = weights[nvars - 2];
10480  backpos = nvars - 2;
10481  break;
10482  case 2:
10483  if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10484  {
10485  sumcoefcase = TRUE;
10486  sumcoef = weights[nvars - 3];
10487  backpos = nvars - 3;
10488  }
10489  else
10490  {
10491  sumcoefcase = FALSE;
10492  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10493  backpos = nvars - 2;
10494  }
10495  break;
10496  default:
10497  assert(k == 3);
10498  if( sumcoefcase )
10499  {
10500  if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10501  {
10502  sumcoef = weights[nvars - 4];
10503  backpos = nvars - 4;
10504  }
10505  else
10506  {
10507  sumcoef = weights[nvars - 1] + weights[nvars - 2];
10508  backpos = nvars - 2;
10509  }
10510  }
10511  else
10512  {
10513  sumcoef = weights[nvars - 3];
10514  backpos = nvars - 3;
10515  }
10516  break;
10517  }
10518 
10519  if( backpos <= pos )
10520  break;
10521 
10522  /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10523  maxweight = weights[pos];
10524  startpos = pos;
10525  while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10526  {
10527  assert(newweight > weights[pos]);
10528 
10529  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10530  SCIPconsGetName(cons), maxweight, newweight);
10531 
10532  consdataChgWeight(consdata, pos, newweight);
10533 
10534  ++pos;
10535  assert(pos < nvars);
10536 
10537  maxweight = weights[pos];
10538 
10539  if( backpos <= pos )
10540  break;
10541  }
10542  (*nchgcoefs) += (pos - startpos);
10543 
10544  /* skip unchangable weights */
10545  while( pos < nvars && weights[pos] + sumcoef == capacity )
10546  ++pos;
10547 
10548  /* check special case were there is only one weight left to tighten
10549  *
10550  * e.g. 95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10551  *
10552  * => 95x1 + 59x2 + 59x3 + 36x4 <= 95
10553  *
10554  * 197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10555  */
10556  if( pos + 1 == backpos && weights[pos] > sumcoef &&
10557  ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10558  {
10559  newweight = capacity - sumcoef;
10560  assert(newweight > weights[pos]);
10561 
10562  SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10563  SCIPconsGetName(cons), maxweight, newweight);
10564 
10565  consdataChgWeight(consdata, pos, newweight);
10566 
10567  break;
10568  }
10569 
10570  if( backpos <= pos )
10571  break;
10572  }
10573  }
10574 
10575  /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10576  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10577  {
10578  if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10579  pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10580  consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10581  {
10582  SCIP_VAR** clqvars;
10583  SCIP_CONS* cliquecons;
10584  char name[SCIP_MAXSTRLEN];
10585  int* clqpart;
10586  int nclqvars;
10587  int nclq;
10588  int len;
10589  int c;
10590  int w;
10591 
10592  assert(!SCIPconsIsDeleted(cons));
10593 
10594  if( pos == consdata->nvars )
10595  {
10596  SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10597 
10598  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10602  SCIPconsIsStickingAtNode(cons)) );
10603 
10604  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10605  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10606  ++(*naddconss);
10607 
10608  /* delete old constraint */
10609  SCIP_CALL( SCIPdelCons(scip, cons) );
10610  ++(*ndelconss);
10611 
10612  return SCIP_OKAY;
10613  }
10614 
10615  len = consdata->nvars - pos;
10616 
10617  /* allocate temporary memory */
10618  SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10619 
10620  /* calculate clique partition */
10621  SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10622  assert(nclq <= len);
10623 
10624 #ifndef NDEBUG
10625  /* clique numbers must be at least as high as the index */
10626  for( w = 0; w < nclq; ++w )
10627  assert(clqpart[w] <= w);
10628 #endif
10629 
10630  SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10631 
10632  /* allocate temporary memory */
10633  SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10634 
10635  /* copy corresponding variables with big coefficients */
10636  for( w = pos - 1; w >= 0; --w )
10637  clqvars[w] = consdata->vars[w];
10638 
10639  /* create for each clique a set-packing constraint */
10640  for( c = 0; c < nclq; ++c )
10641  {
10642  nclqvars = pos;
10643 
10644  for( w = c; w < len; ++w )
10645  {
10646  if( clqpart[w] == c )
10647  {
10648  assert(nclqvars < pos + len - nclq + 1);
10649  clqvars[nclqvars] = consdata->vars[w + pos];
10650  ++nclqvars;
10651  }
10652  }
10653 
10654  assert(nclqvars > 1);
10655 
10656  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10657  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10661  SCIPconsIsStickingAtNode(cons)) );
10662  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10663  SCIPdebugPrintCons(scip, cliquecons, NULL);
10664  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10665  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10666  ++(*naddconss);
10667  }
10668 
10669  /* delete old constraint */
10670  SCIP_CALL( SCIPdelCons(scip, cons) );
10671  ++(*ndelconss);
10672 
10673  SCIPfreeBufferArray(scip, &clqvars);
10674  SCIPfreeBufferArray(scip, &clqpart);
10675 
10676  return SCIP_OKAY;
10677  }
10678  else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10679  {
10680  SCIP_Longint* maxcliqueweights;
10681  SCIP_Longint* newweightvals;
10682  int* newweightidxs;
10683  SCIP_Longint cliqueweightsum;
10684 
10685  SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10686  SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10687  SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10688 
10689  /* repeat as long as changes have been applied */
10690  do
10691  {
10692  int ncliques;
10693  int cliquenum;
10694  SCIP_Bool zeroweights;
10695 
10696  assert(consdata->merged);
10697 
10698  /* sort items, s.t. the heaviest one is in the first position */
10699  sortItems(consdata);
10700 
10701  /* calculate a clique partition */
10702  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10703 
10704  /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10705  if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10706  break;
10707 
10708  /* calculate the maximal weight of the cliques and store the clique type */
10709  cliqueweightsum = 0;
10710  ncliques = 0;
10711 
10712  for( i = 0; i < consdata->nvars; ++i )
10713  {
10714  SCIP_Longint weight;
10715 
10716  cliquenum = consdata->cliquepartition[i];
10717  assert(0 <= cliquenum && cliquenum <= ncliques);
10718 
10719  weight = consdata->weights[i];
10720  assert(weight > 0);
10721 
10722  if( cliquenum == ncliques )
10723  {
10724  maxcliqueweights[ncliques] = weight;
10725  cliqueweightsum += weight;
10726  ++ncliques;
10727  }
10728 
10729  assert(maxcliqueweights[cliquenum] >= weight);
10730  }
10731 
10732  /* apply rule on every clique */
10733  zeroweights = FALSE;
10734  for( i = 0; i < ncliques; ++i )
10735  {
10736  SCIP_Longint delta;
10737 
10738  delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10739  if( delta > 0 )
10740  {
10741  SCIP_Longint newcapacity;
10742 #ifndef NDEBUG
10743  SCIP_Longint newmincliqueweight;
10744 #endif
10745  SCIP_Longint newminweightsuminclique;
10746  SCIP_Bool forceclique;
10747  int nnewweights;
10748  int j;
10749 
10750  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",
10751  SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10752  newcapacity = consdata->capacity - delta;
10753  forceclique = FALSE;
10754  nnewweights = 0;
10755 #ifndef NDEBUG
10756  newmincliqueweight = newcapacity + 1;
10757  for( j = 0; j < i; ++j )
10758  assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10759 #endif
10760  for( j = i; j < consdata->nvars; ++j )
10761  {
10762  if( consdata->cliquepartition[j] == i )
10763  {
10764  newweight = consdata->weights[j] - delta;
10765  newweight = MAX(newweight, 0);
10766 
10767  /* cache the new weight */
10768  assert(nnewweights < consdata->nvars);
10769  newweightvals[nnewweights] = newweight;
10770  newweightidxs[nnewweights] = j;
10771  nnewweights++;
10772 
10773 #ifndef NDEBUG
10774  assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10775  newmincliqueweight = newweight;
10776 #endif
10777  }
10778  }
10779 
10780  /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10781  if( nnewweights > 1 )
10782  {
10783 #ifndef NDEBUG
10784  j = newweightidxs[nnewweights - 2];
10785  assert(0 <= j && j < consdata->nvars);
10786  assert(consdata->cliquepartition[j] == i);
10787  j = newweightidxs[nnewweights - 1];
10788  assert(0 <= j && j < consdata->nvars);
10789  assert(consdata->cliquepartition[j] == i);
10790 #endif
10791 
10792  newminweightsuminclique = newweightvals[nnewweights - 2];
10793  newminweightsuminclique += newweightvals[nnewweights - 1];
10794 
10795  /* check if these new two minimal weights both fit into the knapsack;
10796  * if this is true, we have to add a clique constraint in order to enforce the clique
10797  * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10798  * reduction might be infeasible, i.e., allows additional solutions)
10799  */
10800  if( newminweightsuminclique <= newcapacity )
10801  forceclique = TRUE;
10802  }
10803 
10804  /* check if we really want to apply the change */
10805  if( conshdlrdata->disaggregation || !forceclique )
10806  {
10807  SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10808  consdata->capacity, newcapacity, forceclique);
10809  consdata->capacity = newcapacity;
10810  (*nchgsides)++;
10811 
10812  for( k = 0; k < nnewweights; ++k )
10813  {
10814  j = newweightidxs[k];
10815  assert(0 <= j && j < consdata->nvars);
10816  assert(consdata->cliquepartition[j] == i);
10817 
10818  /* apply the weight change */
10819  SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10820  SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10821  consdataChgWeight(consdata, j, newweightvals[k]);
10822  (*nchgcoefs)++;
10823  assert(!consdata->sorted);
10824  zeroweights = zeroweights || (newweightvals[k] == 0);
10825  }
10826  /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10827  * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10828  * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10829  * knapsack constraint
10830  */
10831  if( forceclique )
10832  {
10833  SCIP_CONS* cliquecons;
10834  char name[SCIP_MAXSTRLEN];
10835  SCIP_VAR** cliquevars;
10836 
10837  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10838  for( k = 0; k < nnewweights; ++k )
10839  cliquevars[k] = consdata->vars[newweightidxs[k]];
10840 
10841  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10842  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10846  SCIPconsIsStickingAtNode(cons)) );
10847  SCIPdebugMsg(scip, " -> adding clique constraint: ");
10848  SCIPdebugPrintCons(scip, cliquecons, NULL);
10849  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10850  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10851  SCIPfreeBufferArray(scip, &cliquevars);
10852  (*naddconss)++;
10853  }
10854  }
10855  }
10856  }
10857  if( zeroweights )
10858  {
10859  SCIP_CALL( removeZeroWeights(scip, cons) );
10860  }
10861  }
10862  while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10863 
10864  /* free temporary memory */
10865  SCIPfreeBufferArray(scip, &newweightidxs);
10866  SCIPfreeBufferArray(scip, &newweightvals);
10867  SCIPfreeBufferArray(scip, &maxcliqueweights);
10868 
10869  /* check for redundancy */
10870  if( consdata->weightsum <= consdata->capacity )
10871  return SCIP_OKAY;
10872  }
10873  }
10874 
10875  /* apply rule (3) */
10876  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10877  {
10878  SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10879  }
10880 
10881  /* check for redundancy */
10882  if( consdata->weightsum <= consdata->capacity )
10883  return SCIP_OKAY;
10884 
10885  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10886  {
10887  /* apply rule (4) (all but smallest weight) */
10888  assert(consdata->merged);
10889  sortItems(consdata);
10890  minweight = consdata->weights[consdata->nvars-1];
10891  for( i = 0; i < consdata->nvars-1; ++i )
10892  {
10893  SCIP_Longint weight;
10894 
10895  weight = consdata->weights[i];
10896  assert(weight >= minweight);
10897  if( minweight + weight > consdata->capacity )
10898  {
10899  if( weight < consdata->capacity )
10900  {
10901  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10902  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10903  assert(consdata->sorted);
10904  consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10905  assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10906  consdata->sorted = TRUE;
10907  (*nchgcoefs)++;
10908  }
10909  }
10910  else
10911  break;
10912  }
10913 
10914  /* apply rule (5) (smallest weight) */
10915  if( consdata->nvars >= 2 )
10916  {
10917  SCIP_Longint weight;
10918 
10919  minweight = consdata->weights[consdata->nvars-2];
10920  weight = consdata->weights[consdata->nvars-1];
10921  assert(minweight >= weight);
10922  if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10923  {
10924  SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10925  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10926  assert(consdata->sorted);
10927  consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10928  assert(minweight >= consdata->weights[consdata->nvars-1]);
10929  consdata->sorted = TRUE;
10930  (*nchgcoefs)++;
10931  }
10932  }
10933  }
10934 
10935  return SCIP_OKAY;
10936 }
10937 
10938 
10939 #ifdef SCIP_DEBUG
10940 static
10941 void printClique(
10942  SCIP_VAR** cliquevars,
10943  int ncliquevars
10944  )
10945 {
10946  int b;
10947  SCIPdebugMessage("adding new Clique: ");
10948  for( b = 0; b < ncliquevars; ++b )
10949  SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10950  SCIPdebugPrintf("\n");
10951 }
10952 #endif
10953 
10954 /** adds negated cliques of the knapsack constraint to the global clique table */
10955 static
10957  SCIP*const scip, /**< SCIP data structure */
10958  SCIP_CONS*const cons, /**< knapsack constraint */
10959  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
10960  int*const nbdchgs /**< pointer to count the number of performed bound changes */
10961  )
10962 {
10963  SCIP_CONSDATA* consdata;
10964  SCIP_CONSHDLRDATA* conshdlrdata;
10965  SCIP_VAR** poscliquevars;
10966  SCIP_VAR** cliquevars;
10967  SCIP_Longint* maxweights;
10968  SCIP_Longint* gainweights;
10969  int* gaincliquepartition;
10970  SCIP_Bool* cliqueused;
10971  SCIP_Longint minactduetonegcliques;
10972  SCIP_Longint freecapacity;
10973  SCIP_Longint lastweight;
10974  SCIP_Longint beforelastweight;
10975  int nposcliquevars;
10976  int ncliquevars;
10977  int nvars;
10978  int nnegcliques;
10979  int lastcliqueused;
10980  int thisnbdchgs;
10981  int v;
10982  int w;
10983 
10984  assert(scip != NULL);
10985  assert(cons != NULL);
10986  assert(cutoff != NULL);
10987  assert(nbdchgs != NULL);
10988 
10989  *cutoff = FALSE;
10990 
10991  consdata = SCIPconsGetData(cons);
10992  assert(consdata != NULL);
10993 
10994  nvars = consdata->nvars;
10995 
10996  /* check whether the cliques have already been added */
10997  if( consdata->cliquesadded || nvars == 0 )
10998  return SCIP_OKAY;
10999 
11000  /* make sure, the items are merged */
11001  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11002  if( *cutoff )
11003  return SCIP_OKAY;
11004 
11005  /* make sure, items are sorted by non-increasing weight */
11006  sortItems(consdata);
11007 
11008  assert(consdata->merged);
11009 
11010  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11011  assert(conshdlrdata != NULL);
11012 
11013  /* calculate a clique partition */
11014  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11015  nnegcliques = consdata->nnegcliques;
11016 
11017  /* if we have no negated cliques, stop */
11018  if( nnegcliques == nvars )
11019  return SCIP_OKAY;
11020 
11021  /* get temporary memory */
11022  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11023  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
11024  SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
11025  SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
11026  SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
11027  SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
11028 
11029  nnegcliques = 0;
11030  minactduetonegcliques = 0;
11031 
11032  /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
11033  for( v = 0; v < nvars; ++v )
11034  {
11035  assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
11036  assert(consdata->weights[v] > 0);
11037 
11038  if( consdata->negcliquepartition[v] == nnegcliques )
11039  {
11040  nnegcliques++;
11041  maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
11042  }
11043  else
11044  minactduetonegcliques += consdata->weights[v];
11045  }
11046 
11047  nposcliquevars = 0;
11048 
11049  /* add cliques, using negated cliques information */
11050  if( minactduetonegcliques > 0 )
11051  {
11052  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11053  freecapacity = consdata->capacity - minactduetonegcliques;
11054 
11055  SCIPdebugPrintCons(scip, cons, NULL);
11056  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",
11057  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11058 
11059  /* calculate possible gain by switching chosen items in negated cliques */
11060  for( v = 0; v < nvars; ++v )
11061  {
11062  if( !cliqueused[consdata->negcliquepartition[v]] )
11063  {
11064  cliqueused[consdata->negcliquepartition[v]] = TRUE;
11065  for( w = v + 1; w < nvars; ++w )
11066  {
11067  /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11068  * weight[w] (which are both in a negated clique) */
11069  if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11070  && consdata->weights[v] > consdata->weights[w] )
11071  {
11072  poscliquevars[nposcliquevars] = consdata->vars[w];
11073  gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11074  gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11075  ++nposcliquevars;
11076  }
11077  }
11078  }
11079  }
11080 
11081  /* try to create negated cliques */
11082  if( nposcliquevars > 0 )
11083  {
11084  /* sort possible gain per substitution of the clique members */
11085  SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11086 
11087  for( v = 0; v < nposcliquevars; ++v )
11088  {
11089  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11090  ncliquevars = 1;
11091  lastweight = gainweights[v];
11092  beforelastweight = -1;
11093  lastcliqueused = gaincliquepartition[v];
11094  /* clear cliqueused to get an unused array */
11095  BMSclearMemoryArray(cliqueused, nnegcliques);
11096  cliqueused[gaincliquepartition[v]] = TRUE;
11097 
11098  /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11099  * in the same negated clique and by taking two of them would exceed the free capacity */
11100  for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11101  {
11102  beforelastweight = lastweight;
11103  lastweight = gainweights[w];
11104  lastcliqueused = gaincliquepartition[w];
11105  cliqueused[gaincliquepartition[w]] = TRUE;
11106  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11107  ++ncliquevars;
11108  }
11109 
11110  if( ncliquevars > 1 )
11111  {
11112  SCIPdebug( printClique(cliquevars, ncliquevars) );
11113  assert(beforelastweight > 0);
11114  /* add the clique to the clique table */
11115  /* this really happens, e.g., on enigma.mps from the short test set */
11116  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11117  if( *cutoff )
11118  goto TERMINATE;
11119  *nbdchgs += thisnbdchgs;
11120 
11121  /* reset last used clique to get slightly different cliques */
11122  cliqueused[lastcliqueused] = FALSE;
11123 
11124  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11125  for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11126  {
11127  SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11128  SCIPdebug( printClique(cliquevars, ncliquevars) );
11129  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11130  if( *cutoff )
11131  goto TERMINATE;
11132  *nbdchgs += thisnbdchgs;
11133  }
11134  }
11135  }
11136  }
11137  }
11138 
11139  TERMINATE:
11140  /* free temporary memory */
11141  SCIPfreeBufferArray(scip, &cliqueused);
11142  SCIPfreeBufferArray(scip, &maxweights);
11143  SCIPfreeBufferArray(scip, &gaincliquepartition);
11144  SCIPfreeBufferArray(scip, &gainweights);
11145  SCIPfreeBufferArray(scip, &cliquevars);
11146  SCIPfreeBufferArray(scip, &poscliquevars);
11147 
11148  return SCIP_OKAY;
11149 }
11150 
11151 /** greedy clique detection by considering weights and capacity
11152  *
11153  * greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11154  * 1) neighboring items which exceed the capacity together => one clique
11155  * 2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11156  */
11157 static
11159  SCIP*const scip, /**< SCIP data structure */
11160  SCIP_VAR** items, /**< array of variable items */
11161  SCIP_Longint* weights, /**< weights of the items */
11162  int nitems, /**< the number of items */
11163  SCIP_Longint capacity, /**< maximum free capacity of the knapsack */
11164  SCIP_Bool sorteditems, /**< are the items sorted by their weights nonincreasing? */
11165  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11166  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11167  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11168  )
11169 {
11170  SCIP_Longint lastweight;
11171  int ncliquevars;
11172  int i;
11173  int thisnbdchgs;
11174 
11175  if( nitems <= 1 )
11176  return SCIP_OKAY;
11177 
11178  /* sort possible gain per substitution of the clique members */
11179  if( ! sorteditems )
11180  SCIPsortDownLongPtr(weights,(void**) items, nitems);
11181 
11182  ncliquevars = 1;
11183  lastweight = weights[0];
11184 
11185  /* taking these two weights together violates the knapsack => include into clique */
11186  for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11187  {
11188  lastweight = weights[i];
11189  ++ncliquevars;
11190  }
11191 
11192  if( ncliquevars > 1 )
11193  {
11194  SCIP_Longint compareweight;
11195  SCIP_VAR** cliquevars;
11196  int compareweightidx;
11197  int minclqsize;
11198  int nnzadded;
11199 
11200  /* add the clique to the clique table */
11201  SCIPdebug( printClique(items, ncliquevars) );
11202  SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11203 
11204  if( *cutoff )
11205  return SCIP_OKAY;
11206 
11207  *nbdchgs += thisnbdchgs;
11208  nnzadded = ncliquevars;
11209 
11210  /* 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)*/
11211  if( ncliquevars == nitems )
11212  return SCIP_OKAY;
11213 
11214  /* copy items in order into buffer array and deduce more cliques */
11215  SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11216 
11217  /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11218  /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11219  compareweightidx = ncliquevars - 2;
11220  assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11221 
11222  /* determine minimum clique size for the following loop */
11223  minclqsize = (int)(cliqueextractfactor * ncliquevars);
11224  minclqsize = MAX(minclqsize, 2);
11225 
11226  /* loop over the remaining variables and the larger items of the first clique until we
11227  * find another clique or reach the size limit */
11228  while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11229  && ncliquevars >= minclqsize /* stop at a given minimum clique size */
11230  && nnzadded <= 2 * nitems /* stop if enough nonzeros were added to the cliquetable */
11231  )
11232  {
11233  compareweight = weights[compareweightidx];
11234  assert(compareweight > 0);
11235 
11236  /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11237  if( compareweight + weights[i] > capacity )
11238  {
11239  assert(compareweightidx == ncliquevars -2);
11240  cliquevars[ncliquevars - 1] = items[i];
11241  SCIPdebug( printClique(cliquevars, ncliquevars) );
11242  SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11243 
11244  nnzadded += ncliquevars;
11245 
11246  /* stop when there is a cutoff */
11247  if( ! (*cutoff) )
11248  *nbdchgs += thisnbdchgs;
11249 
11250  /* go to next smaller item */
11251  ++i;
11252  }
11253  else
11254  {
11255  /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11256  compareweightidx--;
11257  ncliquevars --;
11258  }
11259  }
11260 
11261  SCIPfreeBufferArray(scip, &cliquevars);
11262  }
11263 
11264  return SCIP_OKAY;
11265 }
11266 
11267 /** adds cliques of the knapsack constraint to the global clique table */
11268 static
11270  SCIP*const scip, /**< SCIP data structure */
11271  SCIP_CONS*const cons, /**< knapsack constraint */
11272  SCIP_Real cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11273  SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
11274  int*const nbdchgs /**< pointer to count the number of performed bound changes */
11275  )
11276 {
11277  SCIP_CONSDATA* consdata;
11278  SCIP_CONSHDLRDATA* conshdlrdata;
11279  int i;
11280  SCIP_Longint minactduetonegcliques;
11281  SCIP_Longint freecapacity;
11282  int nnegcliques;
11283  int cliquenum;
11284  SCIP_VAR** poscliquevars;
11285  SCIP_Longint* gainweights;
11286  int nposcliquevars;
11287  SCIP_Longint* secondmaxweights;
11288  int nvars;
11289 
11290  assert(scip != NULL);
11291  assert(cons != NULL);
11292  assert(cutoff != NULL);
11293  assert(nbdchgs != NULL);
11294 
11295  *cutoff = FALSE;
11296 
11297  consdata = SCIPconsGetData(cons);
11298  assert(consdata != NULL);
11299 
11300  nvars = consdata->nvars;
11301 
11302  /* check whether the cliques have already been added */
11303  if( consdata->cliquesadded || nvars == 0 )
11304  return SCIP_OKAY;
11305 
11306  /* make sure, the items are merged */
11307  SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11308  if( *cutoff )
11309  return SCIP_OKAY;
11310 
11311  /* make sure, the items are sorted by non-increasing weight */
11312  sortItems(consdata);
11313 
11314  assert(consdata->merged);
11315 
11316  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11317  assert(conshdlrdata != NULL);
11318 
11319  /* calculate a clique partition */
11320  SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11321  nnegcliques = consdata->nnegcliques;
11322  assert(nnegcliques <= nvars);
11323 
11324  /* get temporary memory */
11325  SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11326  SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11327  BMSclearMemoryArray(gainweights, nvars);
11328  SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11329  BMSclearMemoryArray(secondmaxweights, nnegcliques);
11330 
11331  minactduetonegcliques = 0;
11332 
11333  /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11334  if( nnegcliques < nvars )
11335  {
11336  nnegcliques = 0;
11337 
11338  for( i = 0; i < nvars; ++i )
11339  {
11340  SCIP_Longint weight;
11341 
11342  cliquenum = consdata->negcliquepartition[i];
11343  assert(0 <= cliquenum && cliquenum <= nnegcliques);
11344 
11345  weight = consdata->weights[i];
11346  assert(weight > 0);
11347 
11348  if( cliquenum == nnegcliques )
11349  nnegcliques++;
11350  else
11351  {
11352  minactduetonegcliques += weight;
11353  if( secondmaxweights[cliquenum] == 0 )
11354  secondmaxweights[cliquenum] = weight;
11355  }
11356  }
11357  }
11358 
11359  /* add cliques, using negated cliques information */
11360  if( minactduetonegcliques > 0 )
11361  {
11362  /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11363  freecapacity = consdata->capacity - minactduetonegcliques;
11364 
11365  SCIPdebugPrintCons(scip, cons, NULL);
11366  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",
11367  SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11368 
11369  /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11370  SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11371 
11372  if( *cutoff )
11373  goto TERMINATE;
11374 
11375  nposcliquevars = 0;
11376 
11377  for( i = nvars - 1; i >= 0; --i )
11378  {
11379  /* if we would take the biggest weight instead of the second biggest */
11380  cliquenum = consdata->negcliquepartition[i];
11381  if( consdata->weights[i] > secondmaxweights[cliquenum] )
11382  {
11383  poscliquevars[nposcliquevars] = consdata->vars[i];
11384  gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11385  ++nposcliquevars;
11386  }
11387  }
11388 
11389  /* use the gain weights and free capacity to derive greedily cliques */
11390  if( nposcliquevars > 1 )
11391  {
11392  SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11393 
11394  if( *cutoff )
11395  goto TERMINATE;
11396  }
11397  }
11398 
11399  /* build cliques by using the items with the maximal weights */
11400  SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11401 
11402  TERMINATE:
11403  /* free temporary memory and mark the constraint */
11404  SCIPfreeBufferArray(scip, &secondmaxweights);
11405  SCIPfreeBufferArray(scip, &gainweights);
11406  SCIPfreeBufferArray(scip, &poscliquevars);
11407  consdata->cliquesadded = TRUE;
11408 
11409  return SCIP_OKAY;
11410 }
11411 
11412 
11413 /** gets the key of the given element */
11414 static
11415 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11416 { /*lint --e{715}*/
11417  /* the key is the element itself */
11418  return elem;
11419 }
11420 
11421 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11422  * same coefficients
11423  */
11424 static
11425 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11426 {
11427 #ifndef NDEBUG
11428  SCIP* scip;
11429 #endif
11430  SCIP_CONSDATA* consdata1;
11431  SCIP_CONSDATA* consdata2;
11432  int i;
11434  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11435  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11436  assert(consdata1->sorted);
11437  assert(consdata2->sorted);
11438 #ifndef NDEBUG
11439  scip = (SCIP*)userptr;
11440  assert(scip != NULL);
11441 #endif
11442 
11443  /* checks trivial case */
11444  if( consdata1->nvars != consdata2->nvars )
11445  return FALSE;
11446 
11447  for( i = consdata1->nvars - 1; i >= 0; --i )
11448  {
11449  /* tests if variables are equal */
11450  if( consdata1->vars[i] != consdata2->vars[i] )
11451  {
11452  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11453  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11454  return FALSE;
11455  }
11456  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11457 
11458  /* tests if weights are equal too */
11459  if( consdata1->weights[i] != consdata2->weights[i] )
11460  return FALSE;
11461  }
11462 
11463  return TRUE;
11464 }
11465 
11466 /** returns the hash value of the key */
11467 static
11468 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11469 {
11470 #ifndef NDEBUG
11471  SCIP* scip;
11472 #endif
11473  SCIP_CONSDATA* consdata;
11474  uint64_t firstweight;
11475  int minidx;
11476  int mididx;
11477  int maxidx;
11478 
11479  consdata = SCIPconsGetData((SCIP_CONS*)key);
11480  assert(consdata != NULL);
11481  assert(consdata->nvars > 0);
11482 
11483 #ifndef NDEBUG
11484  scip = (SCIP*)userptr;
11485  assert(scip != NULL);
11486 #endif
11487 
11488  /* sorts the constraints */
11489  sortItems(consdata);
11490 
11491  minidx = SCIPvarGetIndex(consdata->vars[0]);
11492  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11493  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11494  assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11495 
11496  /* hash value depends on vectors of variable indices */
11497  firstweight = (uint64_t)consdata->weights[0];
11498  return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11499 }
11500 
11501 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11502  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11503  */
11504 static
11506  SCIP* scip, /**< SCIP data structure */
11507  BMS_BLKMEM* blkmem, /**< block memory */
11508  SCIP_CONS** conss, /**< constraint set */
11509  int nconss, /**< number of constraints in constraint set */
11510  SCIP_Bool* cutoff, /**< pointer to store whether the problem is infeasible */
11511  int* ndelconss /**< pointer to count number of deleted constraints */
11512  )
11514  SCIP_HASHTABLE* hashtable;
11515  int hashtablesize;
11516  int c;
11517 
11518  assert(scip != NULL);
11519  assert(blkmem != NULL);
11520  assert(conss != NULL);
11521  assert(ndelconss != NULL);
11522 
11523  /* create a hash table for the constraint set */
11524  hashtablesize = nconss;
11525  hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11526  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11527  hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11528 
11529  /* check all constraints in the given set for redundancy */
11530  for( c = nconss - 1; c >= 0; --c )
11531  {
11532  SCIP_CONS* cons0;
11533  SCIP_CONS* cons1;
11534  SCIP_CONSDATA* consdata0;
11535 
11536  cons0 = conss[c];
11537 
11538  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11539  continue;
11540 
11541  consdata0 = SCIPconsGetData(cons0);
11542  assert(consdata0 != NULL);
11543  if( consdata0->nvars == 0 )
11544  {
11545  if( consdata0->capacity < 0 )
11546  {
11547  *cutoff = TRUE;
11548  goto TERMINATE;
11549  }
11550  else
11551  {
11552  SCIP_CALL( SCIPdelCons(scip, cons0) );
11553  ++(*ndelconss);
11554  continue;
11555  }
11556  }
11557 
11558  /* get constraint from current hash table with same variables and same weights as cons0 */
11559  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11560 
11561  if( cons1 != NULL )
11562  {
11563  SCIP_CONS* consstay;
11564  SCIP_CONS* consdel;
11565  SCIP_CONSDATA* consdata1;
11566 
11567  assert(SCIPconsIsActive(cons1));
11568  assert(!SCIPconsIsModifiable(cons1));
11569 
11570  /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11571  * delete old constraints afterwards
11572  */
11573  consdata1 = SCIPconsGetData(cons1);
11574 
11575  assert(consdata1 != NULL);
11576  assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11577 
11578  assert(consdata0->sorted && consdata1->sorted);
11579  assert(consdata0->vars[0] == consdata1->vars[0]);
11580  assert(consdata0->weights[0] == consdata1->weights[0]);
11581 
11582  SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11583  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11584 
11585  /* check which constraint has to stay; */
11586  if( consdata0->capacity < consdata1->capacity )
11587  {
11588  consstay = cons0;
11589  consdel = cons1;
11590 
11591  /* exchange consdel with consstay in hashtable */
11592  SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11593  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11594  }
11595  else
11596  {
11597  consstay = cons1;
11598  consdel = cons0;
11599  }
11600 
11601  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11602  SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11603 
11604  /* delete consdel */
11605  SCIP_CALL( SCIPdelCons(scip, consdel) );
11606  ++(*ndelconss);
11607 
11608  assert(SCIPconsIsActive(consstay));
11609  }
11610  else
11611  {
11612  /* no such constraint in current hash table: insert cons0 into hash table */
11613  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11614  }
11615  }
11616 
11617  TERMINATE:
11618  /* free hash table */
11619  SCIPhashtableFree(&hashtable);
11620 
11621  return SCIP_OKAY;
11622 }
11623 
11624 
11625 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11626  * and removes or changes constraint accordingly
11627  */
11628 static
11630  SCIP* scip, /**< SCIP data structure */
11631  SCIP_CONS** conss, /**< constraint set */
11632  int firstchange, /**< first constraint that changed since last pair preprocessing round */
11633  int chkind, /**< index of constraint to check against all prior indices upto startind */
11634  int* ndelconss /**< pointer to count number of deleted constraints */
11635  )
11636 {
11637  SCIP_CONS* cons0;
11638  SCIP_CONSDATA* consdata0;
11639  int c;
11640 
11641  assert(scip != NULL);
11642  assert(conss != NULL);
11643  assert(firstchange <= chkind);
11644  assert(ndelconss != NULL);
11645 
11646  /* get the constraint to be checked against all prior constraints */
11647  cons0 = conss[chkind];
11648  assert(cons0 != NULL);
11649  assert(SCIPconsIsActive(cons0));
11650  assert(!SCIPconsIsModifiable(cons0));
11651 
11652  consdata0 = SCIPconsGetData(cons0);
11653  assert(consdata0 != NULL);
11654  assert(consdata0->nvars >= 1);
11655  assert(consdata0->merged);
11656 
11657  /* sort the constraint */
11658  sortItems(consdata0);
11659 
11660  /* see #2970 */
11661  if( consdata0->capacity == 0 )
11662  return SCIP_OKAY;
11663 
11664  /* check constraint against all prior constraints */
11665  for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11666  {
11667  SCIP_CONS* cons1;
11668  SCIP_CONSDATA* consdata1;
11669  SCIP_Bool iscons0incons1contained;
11670  SCIP_Bool iscons1incons0contained;
11671  SCIP_Real quotient;
11672  int v;
11673  int v0;
11674  int v1;
11675 
11676  cons1 = conss[c];
11677  assert(cons1 != NULL);
11678  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11679  continue;
11680 
11681  consdata1 = SCIPconsGetData(cons1);
11682  assert(consdata1 != NULL);
11683 
11684  /* if both constraints didn't change since last pair processing, we can ignore the pair */
11685  if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11686  continue;
11687 
11688  assert(consdata1->nvars >= 1);
11689  assert(consdata1->merged);
11690 
11691  /* sort the constraint */
11692  sortItems(consdata1);
11693 
11694  /* see #2970 */
11695  if( consdata1->capacity == 0 )
11696  continue;
11697 
11698  quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11699 
11700  if( consdata0->nvars > consdata1->nvars )
11701  {
11702  iscons0incons1contained = FALSE;
11703  iscons1incons0contained = TRUE;
11704  v = consdata1->nvars - 1;
11705  }
11706  else if( consdata0->nvars < consdata1->nvars )
11707  {
11708  iscons0incons1contained = TRUE;
11709  iscons1incons0contained = FALSE;
11710  v = consdata0->nvars - 1;
11711  }
11712  else
11713  {
11714  iscons0incons1contained = TRUE;
11715  iscons1incons0contained = TRUE;
11716  v = consdata0->nvars - 1;
11717  }
11718 
11719  SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11720 
11721  /* check consdata0 against consdata1:
11722  * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11723  * (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11724  * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11725  * (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11726  */
11727  v0 = consdata0->nvars - 1;
11728  v1 = consdata1->nvars - 1;
11729 
11730  while( v >= 0 )
11731  {
11732  assert(iscons0incons1contained || iscons1incons0contained);
11733 
11734  /* now there are more variables in cons1 left */
11735  if( v1 > v0 )
11736  {
11737  iscons1incons0contained = FALSE;
11738  if( !iscons0incons1contained )
11739  break;
11740  }
11741  /* now there are more variables in cons0 left */
11742  else if( v1 < v0 )
11743  {
11744  iscons0incons1contained = FALSE;
11745  if( !iscons1incons0contained )
11746  break;
11747  }
11748 
11749  assert(v == v0 || v == v1);
11750  assert(v0 >= 0);
11751  assert(v1 >= 0);
11752 
11753  /* both variables are the same */
11754  if( consdata0->vars[v0] == consdata1->vars[v1] )
11755  {
11756  /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11757  if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11758  {
11759  iscons1incons0contained = FALSE;
11760  if( !iscons0incons1contained )
11761  break;
11762  }
11763  /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11764  else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11765  {
11766  iscons0incons1contained = FALSE;
11767  if( !iscons1incons0contained )
11768  break;
11769  }
11770  --v0;
11771  --v1;
11772  --v;
11773  }
11774  else
11775  {
11776  /* both constraints have a variables which is not part of the other constraint, so stop */
11777  if( iscons0incons1contained && iscons1incons0contained )
11778  {
11779  iscons0incons1contained = FALSE;
11780  iscons1incons0contained = FALSE;
11781  break;
11782  }
11783  assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11784  assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11785  /* continue to the next variable */
11786  if( iscons0incons1contained )
11787  --v1;
11788  else
11789  --v0;
11790  }
11791  }
11792  /* neither one constraint was contained in another or we checked all variables of one constraint against the
11793  * other
11794  */
11795  assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11796 
11797  if( iscons1incons0contained )
11798  {
11799  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11800  SCIPdebugPrintCons(scip, cons1, NULL);
11801 
11802  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11803  SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11804 
11805  SCIP_CALL( SCIPdelCons(scip, cons1) );
11806  ++(*ndelconss);
11807  }
11808  else if( iscons0incons1contained )
11809  {
11810  SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11811  SCIPdebugPrintCons(scip, cons0, NULL);
11812 
11813  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11814  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11815 
11816  SCIP_CALL( SCIPdelCons(scip, cons0) );
11817  ++(*ndelconss);
11818  break;
11819  }
11820  }
11821 
11822  return SCIP_OKAY;
11823 }
11824 
11825 /** helper function to enforce constraints */
11826 static
11828  SCIP* scip, /**< SCIP data structure */
11829  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11830  SCIP_CONS** conss, /**< constraints to process */
11831  int nconss, /**< number of constraints */
11832  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11833  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11834  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11835  )
11836 {
11837  SCIP_CONSHDLRDATA* conshdlrdata;
11838  SCIP_Bool violated;
11839  SCIP_Bool cutoff = FALSE;
11840  int maxncuts;
11841  int ncuts = 0;
11842  int i;
11843 
11844  *result = SCIP_FEASIBLE;
11845 
11846  SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11847  sol == NULL ? "LP" : "relaxation");
11848 
11849  /* get maximal number of cuts per round */
11850  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11851  assert(conshdlrdata != NULL);
11852  maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11853 
11854  /* search for violated useful knapsack constraints */
11855  for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11856  {
11857  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11858  if( violated )
11859  {
11860  /* add knapsack constraint as LP row to the relaxation */
11861  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11862  ncuts++;
11863  }
11864  }
11865 
11866  /* as long as no violations were found, search for violated obsolete knapsack constraints */
11867  for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11868  {
11869  SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11870  if( violated )
11871  {
11872  /* add knapsack constraint as LP row to the relaxation */
11873  SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11874  ncuts++;
11875  }
11876  }
11877 
11878  /* adjust the result code */
11879  if ( cutoff )
11880  *result = SCIP_CUTOFF;
11881  else if ( ncuts > 0 )
11882  *result = SCIP_SEPARATED;
11883 
11884  return SCIP_OKAY;
11885 }
11886 
11887 /*
11888  * Linear constraint upgrading
11889  */
11890 
11891 /** creates and captures a knapsack constraint out of a linear inequality */
11892 static
11894  SCIP* scip, /**< SCIP data structure */
11895  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11896  const char* name, /**< name of constraint */
11897  int nvars, /**< number of variables in the constraint */
11898  SCIP_VAR** vars, /**< array with variables of constraint entries */
11899  SCIP_Real* vals, /**< array with inequality coefficients */
11900  SCIP_Real lhs, /**< left hand side of inequality */
11901  SCIP_Real rhs, /**< right hand side of inequality */
11902  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11903  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11904  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11905  * Usually set to TRUE. */
11906  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11907  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11908  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11909  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11910  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11911  * Usually set to TRUE. */
11912  SCIP_Bool local, /**< is constraint only valid locally?
11913  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11914  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11915  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11916  * adds coefficients to this constraint. */
11917  SCIP_Bool dynamic, /**< is constraint subject to aging?
11918  * Usually set to FALSE. Set to TRUE for own cuts which
11919  * are separated as constraints. */
11920  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
11921  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11922  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
11923  * if it may be moved to a more global node?
11924  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11925  )
11926 {
11927  SCIP_VAR** transvars;
11928  SCIP_Longint* weights;
11929  SCIP_Longint capacity;
11930  SCIP_Longint weight;
11931  int mult;
11932  int v;
11933 
11934  assert(nvars == 0 || vars != NULL);
11935  assert(nvars == 0 || vals != NULL);
11936  assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11937 
11938  /* get temporary memory */
11939  SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11940  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11941 
11942  /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11943  * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11944  */
11945  if( SCIPisInfinity(scip, rhs) )
11946  {
11947  mult = -1;
11948  capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11949  }
11950  else
11951  {
11952  mult = +1;
11953  capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11954  }
11955 
11956  /* negate positive or negative variables */
11957  for( v = 0; v < nvars; ++v )
11958  {
11959  assert(SCIPisFeasIntegral(scip, vals[v]));
11960  weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11961  if( weight > 0 )
11962  {
11963  transvars[v] = vars[v];
11964  weights[v] = weight;
11965  }
11966  else
11967  {
11968  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11969  weights[v] = -weight; /*lint !e2704*/
11970  capacity -= weight;
11971  }
11972  assert(transvars[v] != NULL);
11973  }
11974 
11975  /* create the constraint */
11976  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11977  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11978 
11979  /* free temporary memory */
11980  SCIPfreeBufferArray(scip, &weights);
11981  SCIPfreeBufferArray(scip, &transvars);
11982 
11983  return SCIP_OKAY;
11984 }
11985 
11986 /** tries to upgrade a linear constraint into a knapsack constraint */
11987 static
11988 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11989 { /*lint --e{715}*/
11990  SCIP_Bool upgrade;
11991 
11992  assert(upgdcons != NULL);
11993 
11994  /* check, if linear constraint can be upgraded to a knapsack constraint
11995  * - all variables must be binary
11996  * - all coefficients must be integral
11997  * - exactly one of the sides must be infinite
11998  * note that this includes the case of negative capacity, which has been
11999  * observed to occur, e.g., when upgrading a conflict constraint
12000  */
12001  upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
12002  && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
12003  && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
12004 
12005  if( upgrade )
12006  {
12007  SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
12008 
12009  /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
12010  assert(!SCIPconsIsModifiable(cons));
12011  SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
12016  }
12017 
12018  return SCIP_OKAY;
12019 }
12020 
12021 /** adds symmetry information of constraint to a symmetry detection graph */
12022 static
12024  SCIP* scip, /**< SCIP pointer */
12025  SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
12026  SCIP_CONS* cons, /**< constraint */
12027  SYM_GRAPH* graph, /**< symmetry detection graph */
12028  SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
12029  )
12030 {
12031  SCIP_CONSDATA* consdata;
12032  SCIP_VAR** vars;
12033  SCIP_Real* vals;
12034  SCIP_Real constant = 0.0;
12035  SCIP_Real rhs;
12036  int nlocvars;
12037  int nvars;
12038  int i;
12039 
12040  assert(scip != NULL);
12041  assert(cons != NULL);
12042  assert(graph != NULL);
12043  assert(success != NULL);
12044 
12045  consdata = SCIPconsGetData(cons);
12046  assert(consdata != NULL);
12047  assert(graph != NULL);
12048 
12049  /* get active variables of the constraint */
12050  nvars = SCIPgetNVars(scip);
12051  nlocvars = consdata->nvars;
12052 
12053  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
12054  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
12055 
12056  for( i = 0; i < consdata->nvars; ++i )
12057  {
12058  vars[i] = consdata->vars[i];
12059  vals[i] = (SCIP_Real) consdata->weights[i];
12060  }
12061 
12062  SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
12063  rhs = (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons) - constant;
12064 
12065  SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars,
12066  cons, -SCIPinfinity(scip), rhs, success) );
12067 
12068  SCIPfreeBufferArray(scip, &vals);
12069  SCIPfreeBufferArray(scip, &vars);
12070 
12071  return SCIP_OKAY;
12072 }
12073 
12074 /*
12075  * Callback methods of constraint handler
12076  */
12077 
12078 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12079 /**! [SnippetConsCopyKnapsack] */
12080 static
12081 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
12082 { /*lint --e{715}*/
12083  assert(scip != NULL);
12084  assert(conshdlr != NULL);
12085  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12086 
12087  /* call inclusion method of constraint handler */
12090  *valid = TRUE;
12091 
12092  return SCIP_OKAY;
12093 }
12094 /**! [SnippetConsCopyKnapsack] */
12095 
12096 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12097 /**! [SnippetConsFreeKnapsack] */
12098 static
12099 SCIP_DECL_CONSFREE(consFreeKnapsack)
12100 { /*lint --e{715}*/
12101  SCIP_CONSHDLRDATA* conshdlrdata;
12102 
12103  /* free constraint handler data */
12104  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12105  assert(conshdlrdata != NULL);
12106 
12107  SCIPfreeBlockMemory(scip, &conshdlrdata);
12108 
12109  SCIPconshdlrSetData(conshdlr, NULL);
12110 
12111  return SCIP_OKAY;
12112 }
12113 /**! [SnippetConsFreeKnapsack] */
12114 
12115 
12116 /** initialization method of constraint handler (called after problem was transformed) */
12117 static
12118 SCIP_DECL_CONSINIT(consInitKnapsack)
12119 { /*lint --e{715}*/
12120  SCIP_CONSHDLRDATA* conshdlrdata;
12121  int nvars;
12122 
12123  assert( scip != NULL );
12124  assert( conshdlr != NULL );
12125 
12126  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12127  assert(conshdlrdata != NULL);
12128 
12129  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12130  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12131 
12132  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12133  conshdlrdata->reals1size = nvars;
12134 
12135  return SCIP_OKAY;
12136 }
12137 
12138 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12139 static
12140 SCIP_DECL_CONSEXIT(consExitKnapsack)
12141 { /*lint --e{715}*/
12142  SCIP_CONSHDLRDATA* conshdlrdata;
12143 
12144  assert( scip != NULL );
12145  assert( conshdlr != NULL );
12146 
12147  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12148  assert(conshdlrdata != NULL);
12149 
12150  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12151  conshdlrdata->reals1size = 0;
12152 
12153  return SCIP_OKAY;
12154 }
12155 
12156 
12157 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12158 static
12159 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12160 { /*lint --e{715}*/
12161  SCIP_CONSHDLRDATA* conshdlrdata;
12162  int nvars;
12163 
12164  assert(scip != NULL);
12165  assert(conshdlr != NULL);
12166  assert(nconss == 0 || conss != NULL);
12168  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12169  assert(conshdlrdata != NULL);
12170 
12171  /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12172  nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12173 
12174  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12175  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12176  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12177  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12178  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12179  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12180  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12181  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12182 
12183  conshdlrdata->ints1size = nvars;
12184  conshdlrdata->ints2size = nvars;
12185  conshdlrdata->longints1size = nvars;
12186  conshdlrdata->longints2size = nvars;
12187  conshdlrdata->bools1size = nvars;
12188  conshdlrdata->bools2size = nvars;
12189  conshdlrdata->bools3size = nvars;
12190  conshdlrdata->bools4size = nvars;
12191 
12192 #ifdef WITH_CARDINALITY_UPGRADE
12193  conshdlrdata->upgradedcard = FALSE;
12194 #endif
12195 
12196  return SCIP_OKAY;
12197 }
12198 
12199 
12200 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12201 static
12202 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12203 { /*lint --e{715}*/
12204  SCIP_CONSHDLRDATA* conshdlrdata;
12205  int c;
12206 
12207  assert(scip != NULL);
12208  assert(conshdlr != NULL);
12209 
12210  for( c = 0; c < nconss; ++c )
12211  {
12212  if( !SCIPconsIsDeleted(conss[c]) )
12213  {
12214  /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12215  SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12216  }
12217  }
12218 
12219  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12220  assert(conshdlrdata != NULL);
12221 
12222  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12223  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12224  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12225  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12226  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12227  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12228  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12229  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12230 
12231  conshdlrdata->ints1size = 0;
12232  conshdlrdata->ints2size = 0;
12233  conshdlrdata->longints1size = 0;
12234  conshdlrdata->longints2size = 0;
12235  conshdlrdata->bools1size = 0;
12236  conshdlrdata->bools2size = 0;
12237  conshdlrdata->bools3size = 0;
12238  conshdlrdata->bools4size = 0;
12239 
12240  return SCIP_OKAY;
12241 }
12242 
12243 /** solving process initialization method of constraint handler */
12244 static
12245 SCIP_DECL_CONSINITSOL(consInitsolKnapsack)
12246 { /*lint --e{715}*/
12247  /* add nlrow representation to NLP, if NLP had been constructed */
12248  if( SCIPisNLPConstructed(scip) )
12249  {
12250  int c;
12251  for( c = 0; c < nconss; ++c )
12252  {
12253  SCIP_CALL( addNlrow(scip, conss[c]) );
12254  }
12255  }
12256 
12257  return SCIP_OKAY;
12258 }
12259 
12260 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12261 static
12262 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12263 { /*lint --e{715}*/
12264  SCIP_CONSDATA* consdata;
12265  int c;
12266 
12267  assert( scip != NULL );
12268 
12269  /* release the rows and nlrows of all constraints */
12270  for( c = 0; c < nconss; ++c )
12271  {
12272  consdata = SCIPconsGetData(conss[c]);
12273  assert(consdata != NULL);
12274 
12275  if( consdata->row != NULL )
12276  {
12277  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12278  }
12279 
12280  if( consdata->nlrow != NULL )
12281  {
12282  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12283  }
12284  }
12285 
12286  return SCIP_OKAY;
12287 }
12288 
12289 /** frees specific constraint data */
12290 static
12291 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12292 { /*lint --e{715}*/
12293  SCIP_CONSHDLRDATA* conshdlrdata;
12294 
12295  assert(conshdlr != NULL);
12296  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12297 
12298  /* get event handler */
12299  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12300  assert(conshdlrdata != NULL);
12301  assert(conshdlrdata->eventhdlr != NULL);
12302 
12303  /* free knapsack constraint */
12304  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12305 
12306  return SCIP_OKAY;
12307 }
12308 
12309 /** transforms constraint data into data belonging to the transformed problem */
12310 /**! [SnippetConsTransKnapsack]*/
12311 static
12312 SCIP_DECL_CONSTRANS(consTransKnapsack)
12313 { /*lint --e{715}*/
12314  SCIP_CONSHDLRDATA* conshdlrdata;
12315  SCIP_CONSDATA* sourcedata;
12316  SCIP_CONSDATA* targetdata;
12317 
12318  assert(conshdlr != NULL);
12319  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12321  assert(sourcecons != NULL);
12322  assert(targetcons != NULL);
12323 
12324  sourcedata = SCIPconsGetData(sourcecons);
12325  assert(sourcedata != NULL);
12326  assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
12327 
12328  /* get event handler */
12329  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12330  assert(conshdlrdata != NULL);
12331  assert(conshdlrdata->eventhdlr != NULL);
12332 
12333  /* create target constraint data */
12334  SCIP_CALL( consdataCreate(scip, &targetdata,
12335  sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12336 
12337  /* create target constraint */
12338  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12339  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12340  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12341  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12342  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12343 
12344  /* catch events for variables */
12345  SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12346 
12347  return SCIP_OKAY;
12348 }
12349 /**! [SnippetConsTransKnapsack]*/
12350 
12351 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12352 static
12353 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12354 { /*lint --e{715}*/
12355  int i;
12356 
12357  *infeasible = FALSE;
12358 
12359  for( i = 0; i < nconss && !(*infeasible); i++ )
12360  {
12361  assert(SCIPconsIsInitial(conss[i]));
12362  SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12363  }
12364 
12365  return SCIP_OKAY;
12366 }
12367 
12368 /** separation method of constraint handler for LP solutions */
12369 static
12370 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12371 { /*lint --e{715}*/
12372  SCIP_CONSHDLRDATA* conshdlrdata;
12373  SCIP_Bool sepacardinality;
12374  SCIP_Bool cutoff;
12375 
12376  SCIP_Real loclowerbound;
12377  SCIP_Real glblowerbound;
12378  SCIP_Real cutoffbound;
12379  SCIP_Real maxbound;
12380 
12381  int depth;
12382  int nrounds;
12383  int sepafreq;
12384  int sepacardfreq;
12385  int ncuts;
12386  int maxsepacuts;
12387  int i;
12388 
12389  *result = SCIP_DIDNOTRUN;
12390 
12391  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12392  assert(conshdlrdata != NULL);
12393 
12394  depth = SCIPgetDepth(scip);
12395  nrounds = SCIPgetNSepaRounds(scip);
12396 
12397  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12398  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12399 
12400  /* only call the separator a given number of times at each node */
12401  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12402  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12403  return SCIP_OKAY;
12404 
12405  /* check, if we should additionally separate knapsack cuts */
12406  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12407  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12408  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12409  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12410 
12411  /* check dual bound to see if we want to produce knapsack cuts at this node */
12412  loclowerbound = SCIPgetLocalLowerbound(scip);
12413  glblowerbound = SCIPgetLowerbound(scip);
12414  cutoffbound = SCIPgetCutoffbound(scip);
12415  maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12416  sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12417  sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12418 
12419  /* get the maximal number of cuts allowed in a separation round */
12420  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12421 
12422  *result = SCIP_DIDNOTFIND;
12423  ncuts = 0;
12424  cutoff = FALSE;
12425 
12426  /* separate useful constraints */
12427  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12428  {
12429  SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12430  }
12431 
12432  /* adjust return value */
12433  if ( cutoff )
12434  *result = SCIP_CUTOFF;
12435  else if ( ncuts > 0 )
12436  *result = SCIP_SEPARATED;
12437 
12438  return SCIP_OKAY;
12439 }
12440 
12441 
12442 /** separation method of constraint handler for arbitrary primal solutions */
12443 static
12444 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12445 { /*lint --e{715}*/
12446  SCIP_CONSHDLRDATA* conshdlrdata;
12447  SCIP_Bool sepacardinality;
12448  SCIP_Bool cutoff;
12449 
12450  int depth;
12451  int nrounds;
12452  int sepafreq;
12453  int sepacardfreq;
12454  int ncuts;
12455  int maxsepacuts;
12456  int i;
12457 
12458  *result = SCIP_DIDNOTRUN;
12459 
12460  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12461  assert(conshdlrdata != NULL);
12462 
12463  depth = SCIPgetDepth(scip);
12464  nrounds = SCIPgetNSepaRounds(scip);
12465 
12466  SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12467  nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12468 
12469  /* only call the separator a given number of times at each node */
12470  if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12471  || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12472  return SCIP_OKAY;
12473 
12474  /* check, if we should additionally separate knapsack cuts */
12475  sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12476  sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12477  sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12478  && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12479 
12480  /* get the maximal number of cuts allowed in a separation round */
12481  maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12482 
12483  *result = SCIP_DIDNOTFIND;
12484  ncuts = 0;
12485  cutoff = FALSE;
12486 
12487  /* separate useful constraints */
12488  for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12489  {
12490  SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12491  }
12492 
12493  /* adjust return value */
12494  if ( cutoff )
12495  *result = SCIP_CUTOFF;
12496  else if( ncuts > 0 )
12497  *result = SCIP_SEPARATED;
12498 
12499  return SCIP_OKAY;
12500 }
12501 
12502 /** constraint enforcing method of constraint handler for LP solutions */
12503 static
12504 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12505 { /*lint --e{715}*/
12506  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12507 
12508  return SCIP_OKAY;
12509 }
12510 
12511 /** constraint enforcing method of constraint handler for relaxation solutions */
12512 static
12513 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12514 { /*lint --e{715}*/
12515  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12516 
12517  return SCIP_OKAY;
12518 }
12519 
12520 /** constraint enforcing method of constraint handler for pseudo solutions */
12521 static
12522 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12523 { /*lint --e{715}*/
12524  SCIP_Bool violated;
12525  int i;
12526 
12527  for( i = 0; i < nconss; i++ )
12528  {
12529  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12530  if( violated )
12531  {
12532  *result = SCIP_INFEASIBLE;
12533  return SCIP_OKAY;
12534  }
12535  }
12536  *result = SCIP_FEASIBLE;
12537 
12538  return SCIP_OKAY;
12539 }
12540 
12541 /** feasibility check method of constraint handler for integral solutions */
12542 static
12543 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12544 { /*lint --e{715}*/
12545  SCIP_Bool violated;
12546  int i;
12547 
12548  *result = SCIP_FEASIBLE;
12549 
12550  for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12551  {
12552  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12553  if( violated )
12554  *result = SCIP_INFEASIBLE;
12555  }
12556 
12557  return SCIP_OKAY;
12558 }
12559 
12560 /** domain propagation method of constraint handler */
12561 static
12562 SCIP_DECL_CONSPROP(consPropKnapsack)
12563 { /*lint --e{715}*/
12564  SCIP_CONSHDLRDATA* conshdlrdata;
12565  SCIP_Bool cutoff;
12566  SCIP_Bool redundant;
12567  SCIP_Bool inpresolve;
12568  int nfixedvars;
12569  int i;
12571  cutoff = FALSE;
12572  nfixedvars = 0;
12573 
12574  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12575  assert(conshdlrdata != NULL);
12576 
12577  inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12578  assert(!inpresolve || SCIPinProbing(scip));
12579 
12580  /* process useful constraints */
12581  for( i = 0; i < nmarkedconss && !cutoff; i++ )
12582  {
12583  /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12584  * otherwise the multi-aggregation should be resolved
12585  */
12586  if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12587  continue;
12588 #ifndef NDEBUG
12589  else
12590  assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12591 #endif
12592 
12593  SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12594 
12595  /* unmark the constraint to be propagated */
12596  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12597  }
12598 
12599  /* adjust result code */
12600  if( cutoff )
12601  *result = SCIP_CUTOFF;
12602  else if( nfixedvars > 0 )
12603  *result = SCIP_REDUCEDDOM;
12604  else
12605  *result = SCIP_DIDNOTFIND;
12606 
12607  return SCIP_OKAY; /*lint !e438*/
12608 }
12609 
12610 /** presolving method of constraint handler */
12611 static
12612 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12613 { /*lint --e{574,715}*/
12614  SCIP_CONSHDLRDATA* conshdlrdata;
12615  SCIP_CONSDATA* consdata;
12616  SCIP_CONS* cons;
12617  SCIP_Bool cutoff;
12618  SCIP_Bool redundant;
12619  SCIP_Bool success;
12620  int oldnfixedvars;
12621  int oldnchgbds;
12622  int oldndelconss;
12623  int oldnaddconss;
12624  int oldnchgcoefs;
12625  int oldnchgsides;
12626  int firstchange;
12627  int c;
12628  SCIP_Bool newchanges;
12629 
12630  /* remember old preprocessing counters */
12631  cutoff = FALSE;
12632  oldnfixedvars = *nfixedvars;
12633  oldnchgbds = *nchgbds;
12634  oldndelconss = *ndelconss;
12635  oldnaddconss = *naddconss;
12636  oldnchgcoefs = *nchgcoefs;
12637  oldnchgsides = *nchgsides;
12638  firstchange = INT_MAX;
12639 
12640  newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12641 
12642  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12643  assert(conshdlrdata != NULL);
12644 
12645  for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12646  {
12647  int thisnfixedvars;
12648  int thisnchgbds;
12649 
12650  cons = conss[c];
12651  consdata = SCIPconsGetData(cons);
12652  assert(consdata != NULL);
12653 
12654  /* update data structures */
12655  /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12656  if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12657  {
12658  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12659  if( cutoff )
12660  break;
12661  }
12662 
12663  /* force presolving the constraint in the initial round */
12664  if( nrounds == 0 )
12665  consdata->presolvedtiming = 0;
12666  else if( consdata->presolvedtiming >= presoltiming )
12667  continue;
12668 
12669  SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12670  SCIPdebugPrintCons(scip, cons, NULL);
12671  consdata->presolvedtiming = presoltiming;
12672 
12673  thisnfixedvars = *nfixedvars;
12674  thisnchgbds = *nchgbds;
12675 
12676  /* merge constraint, so propagation works better */
12677  SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12678  if( cutoff )
12679  break;
12680 
12681  /* add cliques in the knapsack to the clique table */
12682  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12683  {
12684  SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12685  if( cutoff )
12686  break;
12687  }
12688 
12689  /* propagate constraint */
12690  if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12691  {
12692  SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12693 
12694  if( cutoff )
12695  break;
12696  if( redundant )
12697  {
12698  (*ndelconss)++;
12699  continue;
12700  }
12701  }
12702 
12703  /* remove again all fixed variables, if further fixings were found */
12704  if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12705  {
12706  SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12707  if( cutoff )
12708  break;
12709 
12710  thisnfixedvars = *nfixedvars;
12711  }
12712 
12713  if( !SCIPconsIsModifiable(cons) )
12714  {
12715  /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12716  if( consdata->weightsum <= consdata->capacity )
12717  {
12718  SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12719  SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12720  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12721  continue;
12722  }
12723 
12724  /* divide weights by their greatest common divisor */
12725  normalizeWeights(cons, nchgcoefs, nchgsides);
12726 
12727  /* try to simplify inequalities */
12728  if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12729  {
12730  SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12731  if( cutoff )
12732  break;
12733 
12734  if( SCIPconsIsDeleted(cons) )
12735  continue;
12736 
12737  /* remove again all fixed variables, if further fixings were found */
12738  if( *nfixedvars > thisnfixedvars )
12739  {
12740  SCIP_CALL(applyFixings(scip, cons, &cutoff));
12741  if( cutoff )
12742  break;
12743  }
12744  }
12745 
12746  /* tighten capacity and weights */
12747  SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12748  if( cutoff )
12749  break;
12750 
12751  if( SCIPconsIsActive(cons) )
12752  {
12753  if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12754  {
12755  /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12756  * dual reduction
12757  */
12758  SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12759  if( redundant )
12760  continue;
12761  }
12762 
12763  /* check if knapsack constraint is parallel to objective function */
12764  SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12765  }
12766  }
12767  /* remember the first changed constraint to begin the next aggregation round with */
12768  if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12769  firstchange = c;
12770  }
12771 
12772  /* preprocess pairs of knapsack constraints */
12773  if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12774  {
12775  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12776  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12777  }
12778 
12779  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12780  success = TRUE;
12781  else
12782  success = FALSE;
12783 
12784  if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12785  {
12786  SCIP_Longint npaircomparisons;
12787 
12788  npaircomparisons = 0;
12789  oldndelconss = *ndelconss;
12790  oldnchgsides = *nchgsides;
12791  oldnchgcoefs = *nchgcoefs;
12792 
12793  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12794  {
12795  cons = conss[c];
12796  if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12797  continue;
12798 
12799  npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12800 
12801  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12802 
12803  if( npaircomparisons > NMINCOMPARISONS )
12804  {
12805  if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12806  success = TRUE;
12807  if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12808  ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12809  break;
12810  oldndelconss = *ndelconss;
12811  oldnchgsides = *nchgsides;
12812  oldnchgcoefs = *nchgcoefs;
12813  npaircomparisons = 0;
12814  }
12815  }
12816  }
12817 #ifdef WITH_CARDINALITY_UPGRADE
12818  /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12819  * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12820  * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12821  * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12822  * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12823  * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12824  * as well, we better keep this code disabled. */
12825  /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12826  if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12827  {
12828  SCIP_HASHMAP* varhash;
12829  SCIP_VAR** cardvars;
12830  SCIP_Real* cardweights;
12831  int noldupgdconss;
12832  int nscipvars;
12833  int makeupgrade;
12834 
12835  noldupgdconss = *nupgdconss;
12836  nscipvars = SCIPgetNVars(scip);
12837  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12838  SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12839 
12840  /* set up hash map */
12841  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12842 
12843  /* We loop through all cardinality constraints twice:
12844  * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12845  * knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12846  * locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12847  * - Second, upgrade knapsack constraints to cardinality constraints. */
12848  for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12849  {
12850  for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12851  {
12852  SCIP_CONS* cardcons;
12853  SCIP_VAR** vars;
12854  SCIP_Longint* weights;
12855  int nvars;
12856  int v;
12857 
12858  cons = conss[c];
12859  assert( cons != NULL );
12860  consdata = SCIPconsGetData(cons);
12861  assert( consdata != NULL );
12862 
12863  nvars = consdata->nvars;
12864  vars = consdata->vars;
12865  weights = consdata->weights;
12866 
12867  /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12868  * - all variables must be binary (always true)
12869  * - all coefficients must be 1.0
12870  * - the right hand side must be smaller than nvars
12871  */
12872  if ( consdata->capacity >= nvars )
12873  continue;
12874 
12875  /* the weights are sorted: check first and last weight */
12876  assert( consdata->sorted );
12877  if ( weights[0] != 1 || weights[nvars-1] != 1 )
12878  continue;
12879 
12880  /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12881  for (v = 0; v < nvars; ++v)
12882  {
12883  SCIP_BOUNDTYPE* impltypes;
12884  SCIP_Real* implbounds;
12885  SCIP_VAR** implvars;
12886  SCIP_VAR* var;
12887  int nimpls;
12888  int j;
12889 
12890  var = consdata->vars[v];
12891  assert( var != NULL );
12892  assert( SCIPvarIsBinary(var) );
12893 
12894  /* ignore non-active variables */
12895  if ( ! SCIPvarIsActive(var) )
12896  break;
12897 
12898  /* be sure that implication variable has zero objective */
12899  if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12900  break;
12901 
12902  nimpls = SCIPvarGetNImpls(var, FALSE);
12903  implvars = SCIPvarGetImplVars(var, FALSE);
12904  implbounds = SCIPvarGetImplBounds(var, FALSE);
12905  impltypes = SCIPvarGetImplTypes(var, FALSE);
12906 
12907  for (j = 0; j < nimpls; ++j)
12908  {
12909  /* be sure that continuous variable is fixed to 0 */
12910  if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12911  continue;
12912 
12913  /* cannot currently deal with nonzero fixings */
12914  if ( ! SCIPisZero(scip, implbounds[j]) )
12915  continue;
12916 
12917  /* number of down locks should be one */
12918  if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12919  continue;
12920 
12921  cardvars[v] = implvars[j];
12922  cardweights[v] = (SCIP_Real) v;
12923 
12924  break;
12925  }
12926 
12927  /* found no variable upper bound candidate -> exit */
12928  if ( j >= nimpls )
12929  break;
12930  }
12931 
12932  /* did not find fitting variable upper bound for some variable -> exit */
12933  if ( v < nvars )
12934  break;
12935 
12936  /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12937  * in which the binary variable is involved in */
12938  if ( makeupgrade == 0 )
12939  {
12940  for (v = 0; v < nvars; ++v)
12941  {
12942  if ( SCIPhashmapExists(varhash, vars[v]) )
12943  {
12944  int image;
12945 
12946  image = SCIPhashmapGetImageInt(varhash, vars[v]);
12947  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12948  assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12949  }
12950  else
12951  {
12952  SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12953  assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12954  assert( SCIPhashmapExists(varhash, vars[v]) );
12955  }
12956  }
12957  }
12958  else
12959  {
12960  SCIP_CONS* origcons;
12961 
12962  /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12963  * knapsack constraint coincides with the number of variable up locks */
12964  for (v = 0; v < nvars; ++v)
12965  {
12966  assert( SCIPhashmapExists(varhash, vars[v]) );
12967  if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12968  break;
12969  }
12970  if ( v < nvars )
12971  break;
12972 
12973  /* store that we have upgraded */
12974  conshdlrdata->upgradedcard = TRUE;
12975 
12976  /* at this point we found suitable variable upper bounds */
12977  SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12978 
12979  /* create cardinality constraint */
12980  assert( ! SCIPconsIsModifiable(cons) );
12981  SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12985 #ifdef SCIP_DEBUG
12986  SCIPprintCons(scip, cons, NULL);
12987  SCIPinfoMessage(scip, NULL, "\n");
12988  SCIPprintCons(scip, cardcons, NULL);
12989  SCIPinfoMessage(scip, NULL, "\n");
12990 #endif
12991  SCIP_CALL( SCIPaddCons(scip, cardcons) );
12992  SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12993  ++(*nupgdconss);
12994 
12995  /* delete oknapsack constraint */
12996  SCIP_CALL( SCIPdelCons(scip, cons) );
12997  ++(*ndelconss);
12998 
12999  /* We need to disable the original knapsack constraint, since it might happen that the binary variables
13000  * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
13001  * although the cardinality constraint is satisfied. */
13002  origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
13003  assert( origcons != NULL );
13004  SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
13005 
13006  for (v = 0; v < nvars; ++v)
13007  {
13008  int image;
13009 
13010  assert ( SCIPhashmapExists(varhash, vars[v]) );
13011  image = SCIPhashmapGetImageInt(varhash, vars[v]);
13012  SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
13013  assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
13014  }
13015  }
13016  }
13017  }
13018  SCIPhashmapFree(&varhash);
13019  SCIPfreeBufferArray(scip, &cardweights);
13020  SCIPfreeBufferArray(scip, &cardvars);
13021 
13022  if ( *nupgdconss > noldupgdconss )
13023  success = TRUE;
13024  }
13025 #endif
13026 
13027  if( cutoff )
13028  *result = SCIP_CUTOFF;
13029  else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
13030  *result = SCIP_SUCCESS;
13031  else
13032  *result = SCIP_DIDNOTFIND;
13033 
13034  return SCIP_OKAY;
13035 }
13036 
13037 /** propagation conflict resolving method of constraint handler */
13038 static
13039 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
13040 { /*lint --e{715}*/
13041  SCIP_CONSDATA* consdata;
13042  SCIP_Longint capsum;
13043  int i;
13044 
13045  assert(result != NULL);
13046 
13047  consdata = SCIPconsGetData(cons);
13048  assert(consdata != NULL);
13049 
13050  /* check if we fixed a binary variable to one (due to negated clique) */
13051  if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
13052  {
13053  for( i = 0; i < consdata->nvars; ++i )
13054  {
13055  if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
13056  {
13057  assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
13058  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13059  break;
13060  }
13061  }
13062  assert(i < consdata->nvars);
13063  }
13064  else
13065  {
13066  /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
13067  * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
13068  * knapsack constraint, see one above call of SCIPinferBinvarCons
13069  */
13070  if( inferinfo < 0 )
13071  capsum = 0;
13072  else
13073  {
13074  /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
13075  * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
13076  */
13077  if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
13078  capsum = consdata->weights[inferinfo];
13079  else
13080  {
13081  for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
13082  {}
13083  assert(i < consdata->nvars);
13084  capsum = consdata->weights[i];
13085  }
13086  }
13087 
13088  /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
13089  * the capacity
13090  */
13091  if( capsum <= consdata->capacity )
13092  {
13093  for( i = 0; i < consdata->nvars; i++ )
13094  {
13095  if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
13096  {
13097  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
13098  capsum += consdata->weights[i];
13099  if( capsum > consdata->capacity )
13100  break;
13101  }
13102  }
13103  }
13104  }
13105 
13106  /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
13107  * to zero can included negated clique information. A negated clique means, that at most one of the clique
13108  * variables can be zero. These information can be used to compute a minimum activity of the constraint and
13109  * used to fix variables to zero.
13110  *
13111  * Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
13112  * on global variable bounds. It might even be the case that we reported to many variables which are fixed to
13113  * one.
13114  */
13115  *result = SCIP_SUCCESS;
13116 
13117  return SCIP_OKAY;
13118 }
13119 
13120 /** variable rounding lock method of constraint handler */
13121 /**! [SnippetConsLockKnapsack] */
13122 static
13123 SCIP_DECL_CONSLOCK(consLockKnapsack)
13124 { /*lint --e{715}*/
13125  SCIP_CONSDATA* consdata;
13126  int i;
13127 
13128  consdata = SCIPconsGetData(cons);
13129  assert(consdata != NULL);
13130 
13131  for( i = 0; i < consdata->nvars; i++)
13132  {
13133  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
13134  }
13135 
13136  return SCIP_OKAY;
13137 }
13138 /**! [SnippetConsLockKnapsack] */
13139 
13140 /** constraint activation notification method of constraint handler */
13141 static
13142 SCIP_DECL_CONSACTIVE(consActiveKnapsack)
13143 { /*lint --e{715}*/
13144  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPisNLPConstructed(scip) )
13145  {
13146  SCIP_CALL( addNlrow(scip, cons) );
13147  }
13148 
13149  return SCIP_OKAY;
13151 
13152 /** constraint deactivation notification method of constraint handler */
13153 static
13154 SCIP_DECL_CONSDEACTIVE(consDeactiveKnapsack)
13155 { /*lint --e{715}*/
13156  SCIP_CONSDATA* consdata;
13157 
13158  assert(cons != NULL);
13159 
13160  consdata = SCIPconsGetData(cons);
13161  assert(consdata != NULL);
13163  /* remove row from NLP, if still in solving
13164  * if we are in exitsolve, the whole NLP will be freed anyway
13165  */
13166  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
13167  {
13168  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
13169  }
13170 
13171  return SCIP_OKAY;
13172 }
13173 
13174 /** variable deletion method of constraint handler */
13175 static
13176 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13177 {
13178  assert(scip != NULL);
13179  assert(conshdlr != NULL);
13180  assert(conss != NULL || nconss == 0);
13181 
13182  if( nconss > 0 )
13183  {
13184  SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13185  }
13186 
13187  return SCIP_OKAY;
13188 }
13189 
13190 /** constraint display method of constraint handler */
13191 static
13192 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13193 { /*lint --e{715}*/
13194  SCIP_CONSDATA* consdata;
13195  int i;
13196 
13197  assert( scip != NULL );
13198  assert( conshdlr != NULL );
13199  assert( cons != NULL );
13201  consdata = SCIPconsGetData(cons);
13202  assert(consdata != NULL);
13203 
13204  for( i = 0; i < consdata->nvars; ++i )
13205  {
13206  if( i > 0 )
13207  SCIPinfoMessage(scip, file, " ");
13208  SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13209  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13210  }
13211  SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13212 
13213  return SCIP_OKAY;
13214 }
13215 
13216 /** constraint copying method of constraint handler */
13217 static
13218 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13219 { /*lint --e{715}*/
13220  SCIP_VAR** sourcevars;
13221  SCIP_Longint* weights;
13222  SCIP_Real* coefs;
13223  const char* consname;
13224  int nvars;
13225  int v;
13227  /* get variables and coefficients of the source constraint */
13228  sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13229  nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13230  weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13231 
13232  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13233  for( v = 0; v < nvars; ++v )
13234  coefs[v] = (SCIP_Real) weights[v];
13235 
13236  if( name != NULL )
13237  consname = name;
13238  else
13239  consname = SCIPconsGetName(sourcecons);
13240 
13241  /* copy the logic using the linear constraint copy method */
13242  SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13243  -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13244  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13245  assert(cons != NULL);
13246 
13247  SCIPfreeBufferArray(scip, &coefs);
13248 
13249  return SCIP_OKAY;
13250 }
13251 
13252 /** constraint parsing method of constraint handler */
13253 static
13254 SCIP_DECL_CONSPARSE(consParseKnapsack)
13255 { /*lint --e{715}*/
13256  SCIP_VAR* var;
13257  SCIP_Longint weight;
13258  SCIP_VAR** vars;
13259  SCIP_Longint* weights;
13260  SCIP_Longint capacity;
13261  char* endptr;
13262  int nread;
13263  int nvars;
13264  int varssize;
13265 
13266  assert(scip != NULL);
13267  assert(success != NULL);
13268  assert(str != NULL);
13269  assert(name != NULL);
13270  assert(cons != NULL);
13271 
13272  *success = TRUE;
13273 
13274  nvars = 0;
13275  varssize = 5;
13276  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13277  SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13278 
13279  while( *str != '\0' )
13280  {
13281  /* try to parse coefficient, and use 1 if not successful */
13282  weight = 1;
13283  nread = 0;
13284  sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread);
13285  str += nread;
13286 
13287  /* parse variable name */
13288  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13289 
13290  if( var == NULL )
13291  {
13292  endptr = strchr(endptr, '<');
13293 
13294  if( endptr == NULL )
13295  {
13296  SCIPerrorMessage("no capacity found\n");
13297  *success = FALSE;
13298  }
13299  else
13300  str = endptr;
13301 
13302  break;
13303  }
13304 
13305  str = endptr;
13306 
13307  /* store weight and variable */
13308  if( varssize <= nvars )
13309  {
13310  varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13311  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
13312  SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13313  }
13314 
13315  vars[nvars] = var;
13316  weights[nvars] = weight;
13317  ++nvars;
13318 
13319  /* skip whitespace */
13320  SCIP_CALL( SCIPskipSpace((char**)&str) );
13321  }
13322 
13323  if( *success )
13324  {
13325  if( strncmp(str, "<=", 2) != 0 )
13326  {
13327  SCIPerrorMessage("expected '<=' at begin of '%s'\n", str);
13328  *success = FALSE;
13329  }
13330  else
13331  {
13332  str += 2;
13333  }
13334  }
13335 
13336  if( *success )
13337  {
13338  /* skip whitespace */
13339  SCIP_CALL( SCIPskipSpace((char**)&str) );
13340 
13341  /* coverity[secure_coding] */
13342  if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13343  {
13344  SCIPerrorMessage("error parsing capacity from '%s'\n", str);
13345  *success = FALSE;
13346  }
13347  else
13348  {
13349  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13350  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13351  }
13352  }
13353 
13354  SCIPfreeBufferArray(scip, &vars);
13355  SCIPfreeBufferArray(scip, &weights);
13356 
13357  return SCIP_OKAY;
13358 }
13359 
13360 /** constraint method of constraint handler which returns the variables (if possible) */
13361 static
13362 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13363 { /*lint --e{715}*/
13364  SCIP_CONSDATA* consdata;
13365 
13366  consdata = SCIPconsGetData(cons);
13367  assert(consdata != NULL);
13368 
13369  if( varssize < consdata->nvars )
13370  (*success) = FALSE;
13371  else
13372  {
13373  assert(vars != NULL);
13374 
13375  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13376  (*success) = TRUE;
13377  }
13378 
13379  return SCIP_OKAY;
13380 }
13381 
13382 /** constraint method of constraint handler which returns the number of variables (if possible) */
13383 static
13384 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13385 { /*lint --e{715}*/
13386  SCIP_CONSDATA* consdata;
13387 
13388  consdata = SCIPconsGetData(cons);
13389  assert(consdata != NULL);
13390 
13391  (*nvars) = consdata->nvars;
13392  (*success) = TRUE;
13393 
13394  return SCIP_OKAY;
13395 }
13396 
13397 /** constraint handler method which returns the permutation symmetry detection graph of a constraint */
13398 static
13399 SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphKnapsack)
13400 { /*lint --e{715}*/
13401  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
13402 
13403  return SCIP_OKAY;
13404 }
13405 
13406 /** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
13407 static
13408 SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphKnapsack)
13409 { /*lint --e{715}*/
13410  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
13411 
13412  return SCIP_OKAY;
13413 }
13414 
13415 /*
13416  * Event handler
13417  */
13418 
13419 /** execution method of bound change event handler */
13420 static
13421 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13422 { /*lint --e{715}*/
13423  SCIP_CONSDATA* consdata;
13424 
13425  assert(eventdata != NULL);
13426  assert(eventdata->cons != NULL);
13427 
13428  consdata = SCIPconsGetData(eventdata->cons);
13429  assert(consdata != NULL);
13430 
13431  switch( SCIPeventGetType(event) )
13432  {
13434  consdata->onesweightsum += eventdata->weight;
13435  consdata->presolvedtiming = 0;
13436  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13437  break;
13439  consdata->onesweightsum -= eventdata->weight;
13440  break;
13442  consdata->presolvedtiming = 0;
13443  SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13444  break;
13445  case SCIP_EVENTTYPE_VARFIXED: /* the variable should be removed from the constraint in presolving */
13446  if( !consdata->existmultaggr )
13447  {
13448  SCIP_VAR* var;
13449  var = SCIPeventGetVar(event);
13450  assert(var != NULL);
13451 
13452  /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13454  {
13455  consdata->existmultaggr = TRUE;
13456  consdata->merged = FALSE;
13457  }
13458  else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13460  consdata->merged = FALSE;
13461  }
13462  /*lint -fallthrough*/
13463  case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13464  consdata->presolvedtiming = 0;
13465  break;
13467  consdata->varsdeleted = TRUE;
13468  break;
13469  default:
13470  SCIPerrorMessage("invalid event type %" SCIP_EVENTTYPE_FORMAT "\n", SCIPeventGetType(event));
13471  return SCIP_INVALIDDATA;
13472  }
13473 
13474  return SCIP_OKAY;
13475 }
13476 
13477 
13478 /*
13479  * constraint specific interface methods
13480  */
13481 
13482 /** creates the handler for knapsack constraints and includes it in SCIP */
13484  SCIP* scip /**< SCIP data structure */
13485  )
13486 {
13487  SCIP_EVENTHDLRDATA* eventhdlrdata;
13488  SCIP_CONSHDLRDATA* conshdlrdata;
13489  SCIP_CONSHDLR* conshdlr;
13490 
13491  /* create knapsack constraint handler data */
13492  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13493 
13494  /* include event handler for bound change events */
13495  eventhdlrdata = NULL;
13496  conshdlrdata->eventhdlr = NULL;
13497  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13498  eventExecKnapsack, eventhdlrdata) );
13499 
13500  /* get event handler for bound change events */
13501  if( conshdlrdata->eventhdlr == NULL )
13502  {
13503  SCIPerrorMessage("event handler for knapsack constraints not found\n");
13504  return SCIP_PLUGINNOTFOUND;
13505  }
13506 
13507  /* include constraint handler */
13510  consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13511  conshdlrdata) );
13512 
13513  assert(conshdlr != NULL);
13514 
13515  /* set non-fundamental callbacks via specific setter functions */
13516  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13517  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveKnapsack) );
13518  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveKnapsack) );
13519  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13520  SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13521  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13522  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13523  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolKnapsack) );
13524  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13525  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13526  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13527  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13528  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13529  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13530  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13531  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13532  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13533  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13534  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13536  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13537  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13539  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13540  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13541  SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphKnapsack) );
13542  SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphKnapsack) );
13543 
13544  if( SCIPfindConshdlr(scip,"linear") != NULL )
13545  {
13546  /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13548  }
13549 
13550  /* add knapsack constraint handler parameters */
13551  SCIP_CALL( SCIPaddIntParam(scip,
13552  "constraints/" CONSHDLR_NAME "/sepacardfreq",
13553  "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13554  &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13556  "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13557  "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13558  &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13560  "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13561  "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13562  &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13563  SCIP_CALL( SCIPaddIntParam(scip,
13564  "constraints/" CONSHDLR_NAME "/maxrounds",
13565  "maximal number of separation rounds per node (-1: unlimited)",
13566  &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13567  SCIP_CALL( SCIPaddIntParam(scip,
13568  "constraints/" CONSHDLR_NAME "/maxroundsroot",
13569  "maximal number of separation rounds per node in the root node (-1: unlimited)",
13570  &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13571  SCIP_CALL( SCIPaddIntParam(scip,
13572  "constraints/" CONSHDLR_NAME "/maxsepacuts",
13573  "maximal number of cuts separated per separation round",
13574  &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13575  SCIP_CALL( SCIPaddIntParam(scip,
13576  "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13577  "maximal number of cuts separated per separation round in the root node",
13578  &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13580  "constraints/" CONSHDLR_NAME "/disaggregation",
13581  "should disaggregation of knapsack constraints be allowed in preprocessing?",
13582  &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13584  "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13585  "should presolving try to simplify knapsacks",
13586  &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13588  "constraints/" CONSHDLR_NAME "/negatedclique",
13589  "should negated clique information be used in solving process",
13590  &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13592  "constraints/" CONSHDLR_NAME "/presolpairwise",
13593  "should pairwise constraint comparison be performed in presolving?",
13594  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13596  "constraints/" CONSHDLR_NAME "/presolusehashing",
13597  "should hash table be used for detecting redundant constraints in advance",
13598  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13600  "constraints/" CONSHDLR_NAME "/dualpresolving",
13601  "should dual presolving steps be performed?",
13602  &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13604  "constraints/" CONSHDLR_NAME "/usegubs",
13605  "should GUB information be used for separation?",
13606  &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13608  "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13609  "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13610  &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13612  "constraints/" CONSHDLR_NAME "/detectlowerbound",
13613  "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13614  &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13616  "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13617  "should clique partition information be updated when old partition seems outdated?",
13618  &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13620  "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13621  "factor on the growth of global cliques to decide when to update a previous "
13622  "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13623  &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13624 #ifdef WITH_CARDINALITY_UPGRADE
13626  "constraints/" CONSHDLR_NAME "/upgdcardinality",
13627  "if TRUE then try to update knapsack constraints to cardinality constraints",
13628  &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13629 #endif
13630  return SCIP_OKAY;
13631 }
13632 
13633 /** creates and captures a knapsack constraint
13634  *
13635  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13636  */
13637 /**! [SnippetConsCreationKnapsack] */
13639  SCIP* scip, /**< SCIP data structure */
13640  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13641  const char* name, /**< name of constraint */
13642  int nvars, /**< number of items in the knapsack */
13643  SCIP_VAR** vars, /**< array with item variables */
13644  SCIP_Longint* weights, /**< array with item weights */
13645  SCIP_Longint capacity, /**< capacity of knapsack (right hand side of inequality) */
13646  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13647  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13648  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13649  * Usually set to TRUE. */
13650  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13651  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13652  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13653  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13654  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13655  * Usually set to TRUE. */
13656  SCIP_Bool local, /**< is constraint only valid locally?
13657  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13658  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13659  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13660  * adds coefficients to this constraint. */
13661  SCIP_Bool dynamic, /**< is constraint subject to aging?
13662  * Usually set to FALSE. Set to TRUE for own cuts which
13663  * are separated as constraints. */
13664  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13665  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13666  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13667  * if it may be moved to a more global node?
13668  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13669  )
13670 {
13671  SCIP_CONSHDLRDATA* conshdlrdata;
13672  SCIP_CONSHDLR* conshdlr;
13673  SCIP_CONSDATA* consdata;
13674 
13675  /* find the knapsack constraint handler */
13676  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13677  if( conshdlr == NULL )
13678  {
13679  SCIPerrorMessage("knapsack constraint handler not found\n");
13680  return SCIP_PLUGINNOTFOUND;
13681  }
13682 
13683  /* get event handler */
13684  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13685  assert(conshdlrdata != NULL);
13686  assert(conshdlrdata->eventhdlr != NULL);
13687 
13688  /* create constraint data */
13689  SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13690 
13691  /* create constraint */
13692  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13693  local, modifiable, dynamic, removable, stickingatnode) );
13694 
13695  /* catch events for variables */
13696  if( SCIPisTransformed(scip) )
13697  {
13698  SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13699  }
13700 
13701  return SCIP_OKAY;
13702 }
13703 /**! [SnippetConsCreationKnapsack] */
13704 
13705 /** creates and captures a knapsack constraint
13706  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13707  * method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13708  *
13709  * @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13710  *
13711  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13712  */
13714  SCIP* scip, /**< SCIP data structure */
13715  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13716  const char* name, /**< name of constraint */
13717  int nvars, /**< number of items in the knapsack */
13718  SCIP_VAR** vars, /**< array with item variables */
13719  SCIP_Longint* weights, /**< array with item weights */
13720  SCIP_Longint capacity /**< capacity of knapsack */
13721  )
13722 {
13723  assert(scip != NULL);
13724 
13725  SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13726  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13727 
13728  return SCIP_OKAY;
13729 }
13730 
13731 /** adds new item to knapsack constraint */
13733  SCIP* scip, /**< SCIP data structure */
13734  SCIP_CONS* cons, /**< constraint data */
13735  SCIP_VAR* var, /**< item variable */
13736  SCIP_Longint weight /**< item weight */
13737  )
13738 {
13739  assert(var != NULL);
13740  assert(scip != NULL);
13741 
13742  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13743  {
13744  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13745  return SCIP_INVALIDDATA;
13746  }
13747 
13748  SCIP_CALL( addCoef(scip, cons, var, weight) );
13749 
13750  return SCIP_OKAY;
13751 }
13752 
13753 /** gets the capacity of the knapsack constraint */
13755  SCIP* scip, /**< SCIP data structure */
13756  SCIP_CONS* cons /**< constraint data */
13757  )
13758 {
13759  SCIP_CONSDATA* consdata;
13760 
13761  assert(scip != NULL);
13763  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13764  {
13765  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13766  SCIPABORT();
13767  return 0; /*lint !e527*/
13768  }
13769 
13770  consdata = SCIPconsGetData(cons);
13771  assert(consdata != NULL);
13772 
13773  return consdata->capacity;
13774 }
13775 
13776 /** changes capacity of the knapsack constraint
13777  *
13778  * @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13779  */
13781  SCIP* scip, /**< SCIP data structure */
13782  SCIP_CONS* cons, /**< constraint data */
13783  SCIP_Longint capacity /**< new capacity of knapsack */
13784  )
13785 {
13786  SCIP_CONSDATA* consdata;
13787 
13788  assert(scip != NULL);
13789 
13790  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13791  {
13792  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13793  return SCIP_INVALIDDATA;
13794  }
13795 
13796  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13797  {
13798  SCIPerrorMessage("method can only be called during problem creation stage\n");
13799  return SCIP_INVALIDDATA;
13800  }
13801 
13802  consdata = SCIPconsGetData(cons);
13803  assert(consdata != NULL);
13804 
13805  consdata->capacity = capacity;
13806 
13807  return SCIP_OKAY;
13808 }
13809 
13810 /** gets the number of items in the knapsack constraint */
13812  SCIP* scip, /**< SCIP data structure */
13813  SCIP_CONS* cons /**< constraint data */
13814  )
13815 {
13816  SCIP_CONSDATA* consdata;
13817 
13818  assert(scip != NULL);
13820  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13821  {
13822  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13823  SCIPABORT();
13824  return -1; /*lint !e527*/
13825  }
13826 
13827  consdata = SCIPconsGetData(cons);
13828  assert(consdata != NULL);
13829 
13830  return consdata->nvars;
13831 }
13832 
13833 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
13835  SCIP* scip, /**< SCIP data structure */
13836  SCIP_CONS* cons /**< constraint data */
13837  )
13838 {
13839  SCIP_CONSDATA* consdata;
13840 
13841  assert(scip != NULL);
13843  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13844  {
13845  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13846  SCIPABORT();
13847  return NULL; /*lint !e527*/
13848  }
13849 
13850  consdata = SCIPconsGetData(cons);
13851  assert(consdata != NULL);
13852 
13853  return consdata->vars;
13854 }
13855 
13856 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
13858  SCIP* scip, /**< SCIP data structure */
13859  SCIP_CONS* cons /**< constraint data */
13860  )
13861 {
13862  SCIP_CONSDATA* consdata;
13863 
13864  assert(scip != NULL);
13866  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13867  {
13868  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13869  SCIPABORT();
13870  return NULL; /*lint !e527*/
13871  }
13872 
13873  consdata = SCIPconsGetData(cons);
13874  assert(consdata != NULL);
13875 
13876  return consdata->weights;
13877 }
13878 
13879 /** gets the dual solution of the knapsack constraint in the current LP */
13881  SCIP* scip, /**< SCIP data structure */
13882  SCIP_CONS* cons /**< constraint data */
13883  )
13884 {
13885  SCIP_CONSDATA* consdata;
13886 
13887  assert(scip != NULL);
13889  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13890  {
13891  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13892  SCIPABORT();
13893  return SCIP_INVALID; /*lint !e527*/
13894  }
13895 
13896  consdata = SCIPconsGetData(cons);
13897  assert(consdata != NULL);
13898 
13899  if( consdata->row != NULL )
13900  return SCIProwGetDualsol(consdata->row);
13901  else
13902  return 0.0;
13903 }
13904 
13905 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
13907  SCIP* scip, /**< SCIP data structure */
13908  SCIP_CONS* cons /**< constraint data */
13909  )
13910 {
13911  SCIP_CONSDATA* consdata;
13912 
13913  assert(scip != NULL);
13915  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13916  {
13917  SCIPerrorMessage("constraint is not a knapsack constraint\n");
13918  SCIPABORT();
13919  return SCIP_INVALID; /*lint !e527*/
13920  }
13921 
13922  consdata = SCIPconsGetData(cons);
13923  assert(consdata != NULL);
13924 
13925  if( consdata->row != NULL )
13926  return SCIProwGetDualfarkas(consdata->row);
13927  else
13928  return 0.0;
13929 }
13930 
13931 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13932  * the user must not modify the row!
13933  */
13935  SCIP* scip, /**< SCIP data structure */
13936  SCIP_CONS* cons /**< constraint data */
13937  )
13938 {
13939  SCIP_CONSDATA* consdata;
13940 
13941  assert(scip != NULL);
13943  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13944  {
13945  SCIPerrorMessage("constraint is not a knapsack\n");
13946  SCIPABORT();
13947  return NULL; /*lint !e527*/
13948  }
13949 
13950  consdata = SCIPconsGetData(cons);
13951  assert(consdata != NULL);
13952 
13953  return consdata->row;
13954 }
13955 
13956 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
13958  SCIP* scip, /**< SCIP data structure */
13959  SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
13960  SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
13961  )
13962 {
13963  SCIP_CONSHDLR* conshdlr;
13964  SCIP_CONS** conss;
13965  int nconss;
13966  int i;
13967 
13968  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13969  if( conshdlr == NULL )
13970  return SCIP_OKAY;
13971 
13972  assert(infeasible != NULL);
13973  *infeasible = FALSE;
13974 
13975  nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13976  conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13977 
13978  for( i = 0; i < nconss; ++i )
13979  {
13980  SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13981 
13982  if( *infeasible )
13983  break;
13984  }
13985 
13986  return SCIP_OKAY;
13987 }
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:1695
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:5205
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:2130
#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:1599
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:1994
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:1562
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:1250
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:5322
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:590
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:1482
#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:4261
#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:6923
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:627
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:4439
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:7258
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:8278
#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:4353
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:60
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:7577
#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:7477
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1216
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:718
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:8631
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:5725
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:1529
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