1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   cons_knapsack.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief  Constraint handler for knapsack constraints of the form  \f$a^T x \le b\f$, x binary and \f$a \ge 0\f$.
19  * @author Tobias Achterberg
20  * @author Xin Liu
21  * @author Kati Wolter
22  * @author Michael Winkler
23  * @author Tobias Fischer
24  */
25 
26 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
27 
28 #include "blockmemshell/memory.h"
29 #include "scip/cons_knapsack.h"
30 #include "scip/cons_linear.h"
31 #include "scip/cons_logicor.h"
32 #include "scip/cons_setppc.h"
33 #include "scip/pub_cons.h"
34 #include "scip/pub_event.h"
35 #include "scip/pub_implics.h"
36 #include "scip/pub_lp.h"
37 #include "scip/pub_message.h"
38 #include "scip/pub_misc.h"
39 #include "scip/pub_misc_select.h"
40 #include "scip/pub_misc_sort.h"
41 #include "scip/pub_sepa.h"
42 #include "scip/pub_var.h"
43 #include "scip/scip_branch.h"
44 #include "scip/scip_conflict.h"
45 #include "scip/scip_cons.h"
46 #include "scip/scip_copy.h"
47 #include "scip/scip_cut.h"
48 #include "scip/scip_event.h"
49 #include "scip/scip_general.h"
50 #include "scip/scip_lp.h"
51 #include "scip/scip_mem.h"
52 #include "scip/scip_message.h"
53 #include "scip/scip_numerics.h"
54 #include "scip/scip_param.h"
55 #include "scip/scip_prob.h"
56 #include "scip/scip_probing.h"
57 #include "scip/scip_sol.h"
58 #include "scip/scip_solvingstats.h"
59 #include "scip/scip_tree.h"
60 #include "scip/scip_var.h"
61 #include <ctype.h>
62 #include <string.h>
63 
64 #ifdef WITH_CARDINALITY_UPGRADE
65 #include "scip/cons_cardinality.h"
66 #endif
67 
68 /* constraint handler properties */
69 #define CONSHDLR_NAME          "knapsack"
70 #define CONSHDLR_DESC          "knapsack constraint of the form  a^T x <= b, x binary and a >= 0"
71 #define CONSHDLR_SEPAPRIORITY   +600000 /**< priority of the constraint handler for separation */
72 #define CONSHDLR_ENFOPRIORITY   -600000 /**< priority of the constraint handler for constraint enforcing */
73 #define CONSHDLR_CHECKPRIORITY  -600000 /**< priority of the constraint handler for checking feasibility */
74 #define CONSHDLR_SEPAFREQ             0 /**< frequency for separating cuts; zero means to separate only in the root node */
75 #define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
76 #define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
77                                          *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
78 #define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
79 #define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
80 #define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
81 #define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
82 
83 #define CONSHDLR_PRESOLTIMING            SCIP_PRESOLTIMING_ALWAYS
84 #define CONSHDLR_PROP_TIMING             SCIP_PROPTIMING_BEFORELP
85 
86 #define EVENTHDLR_NAME         "knapsack"
87 #define EVENTHDLR_DESC         "bound change event handler for knapsack constraints"
88 #define EVENTTYPE_KNAPSACK SCIP_EVENTTYPE_LBCHANGED \
89                          | SCIP_EVENTTYPE_UBTIGHTENED \
90                          | SCIP_EVENTTYPE_VARFIXED \
91                          | SCIP_EVENTTYPE_VARDELETED \
92                          | SCIP_EVENTTYPE_IMPLADDED /**< variable events that should be caught by the event handler */
93 
94 #define LINCONSUPGD_PRIORITY    +100000 /**< priority of the constraint handler for upgrading of linear constraints */
95 
96 #define MAX_USECLIQUES_SIZE        1000 /**< maximal number of items in knapsack where clique information is used */
97 #define MAX_ZEROITEMS_SIZE        10000 /**< maximal number of items to store in the zero list in preprocessing */
98 
99 #define KNAPSACKRELAX_MAXDELTA        0.1 /**< maximal allowed rounding distance for scaling in knapsack relaxation */
100 #define KNAPSACKRELAX_MAXDNOM      1000LL /**< maximal allowed denominator in knapsack rational relaxation */
101 #define KNAPSACKRELAX_MAXSCALE     1000.0 /**< maximal allowed scaling factor in knapsack rational relaxation */
102 
103 #define DEFAULT_SEPACARDFREQ          1 /**< multiplier on separation frequency, how often knapsack cuts are separated */
104 #define DEFAULT_MAXROUNDS             5 /**< maximal number of separation rounds per node (-1: unlimited) */
105 #define DEFAULT_MAXROUNDSROOT        -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
106 #define DEFAULT_MAXSEPACUTS          50 /**< maximal number of cuts separated per separation round */
107 #define DEFAULT_MAXSEPACUTSROOT     200 /**< maximal number of cuts separated per separation round in the root node */
108 #define DEFAULT_MAXCARDBOUNDDIST    0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
109                                          *   to best node's dual bound for separating knapsack cuts */
110 #define DEFAULT_DISAGGREGATION     TRUE /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
111 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE/**< should presolving try to simplify knapsacks */
112 #define DEFAULT_NEGATEDCLIQUE      TRUE /**< should negated clique information be used in solving process */
113 
114 #define MAXABSVBCOEF               1e+5 /**< maximal absolute coefficient in variable bounds used for knapsack relaxation */
115 #define USESUPADDLIFT             FALSE /**< should lifted minimal cover inequalities using superadditive up-lifting be separated in addition */
116 
117 #define DEFAULT_PRESOLUSEHASHING   TRUE /**< should hash table be used for detecting redundant constraints in advance */
118 #define HASHSIZE_KNAPSACKCONS       500 /**< minimal size of hash table in linear constraint tables */
119 
120 #define DEFAULT_PRESOLPAIRWISE     TRUE /**< should pairwise constraint comparison be performed in presolving? */
121 #define NMINCOMPARISONS          200000 /**< number for minimal pairwise presolving comparisons */
122 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
123                                          *   comparison round */
124 #define DEFAULT_DUALPRESOLVING     TRUE /**< should dual presolving steps be performed? */
125 #define DEFAULT_DETECTCUTOFFBOUND  TRUE /**< should presolving try to detect constraints parallel to the objective
126                                          *   function defining an upper bound and prevent these constraints from
127                                          *   entering the LP */
128 #define DEFAULT_DETECTLOWERBOUND TRUE   /**< should presolving try to detect constraints parallel to the objective
129                                          *   function defining a lower bound and prevent these constraints from
130                                          *   entering the LP */
131 #define DEFAULT_CLIQUEEXTRACTFACTOR 0.5 /**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
132 #define MAXCOVERSIZEITERLEWI       1000 /**< maximal size for which LEWI are iteratively separated by reducing the feasible set */
133 
134 #define DEFAULT_USEGUBS           FALSE /**< should GUB information be used for separation? */
135 #define GUBCONSGROWVALUE              6 /**< memory growing value for GUB constraint array */
136 #define GUBSPLITGNC1GUBS          FALSE /**< should GNC1 GUB conss without F vars be split into GOC1 and GR GUB conss? */
137 #define DEFAULT_CLQPARTUPDATEFAC   1.5  /**< factor on the growth of global cliques to decide when to update a previous
138                                          *   (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
139 #define DEFAULT_UPDATECLIQUEPARTITIONS FALSE /**< should clique partition information be updated when old partition seems outdated? */
140 #define MAXNCLIQUEVARSCOMP 1000000      /**< limit on number of pairwise comparisons in clique partitioning algorithm */
141 #ifdef WITH_CARDINALITY_UPGRADE
142 #define DEFAULT_UPGDCARDINALITY   FALSE /**< if TRUE then try to update knapsack constraints to cardinality constraints */
143 #endif
144 
145 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
146 
147 /*
148  * Data structures
149  */
150 
151 /** constraint handler data */
152 struct SCIP_ConshdlrData
153 {
154    int*                  ints1;              /**< cleared memory array, all entries are set to zero in initpre, if you use this
155                                               *   you have to clear it at the end, exists only in presolving stage */
156    int*                  ints2;              /**< cleared memory array, all entries are set to zero in initpre, if you use this
157                                               *   you have to clear it at the end, exists only in presolving stage */
158    SCIP_Longint*         longints1;          /**< cleared memory array, all entries are set to zero in initpre, if you use this
159                                               *   you have to clear it at the end, exists only in presolving stage */
160    SCIP_Longint*         longints2;          /**< cleared memory array, all entries are set to zero in initpre, if you use this
161                                               *   you have to clear it at the end, exists only in presolving stage */
162    SCIP_Bool*            bools1;             /**< cleared memory array, all entries are set to zero in initpre, if you use this
163                                               *   you have to clear it at the end, exists only in presolving stage */
164    SCIP_Bool*            bools2;             /**< cleared memory array, all entries are set to zero in initpre, if you use this
165                                               *   you have to clear it at the end, exists only in presolving stage */
166    SCIP_Bool*            bools3;             /**< cleared memory array, all entries are set to zero in initpre, if you use this
167                                               *   you have to clear it at the end, exists only in presolving stage */
168    SCIP_Bool*            bools4;             /**< 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_Real*            reals1;             /**< cleared memory array, all entries are set to zero in consinit, if you use this
171                                               *   you have to clear it at the end */
172    int                   ints1size;          /**< size of ints1 array */
173    int                   ints2size;          /**< size of ints2 array */
174    int                   longints1size;      /**< size of longints1 array */
175    int                   longints2size;      /**< size of longints2 array */
176    int                   bools1size;         /**< size of bools1 array */
177    int                   bools2size;         /**< size of bools2 array */
178    int                   bools3size;         /**< size of bools3 array */
179    int                   bools4size;         /**< size of bools4 array */
180    int                   reals1size;         /**< size of reals1 array */
181    SCIP_EVENTHDLR*       eventhdlr;          /**< event handler for bound change events */
182    SCIP_Real             maxcardbounddist;   /**< maximal relative distance from current node's dual bound to primal bound compared
183                                               *   to best node's dual bound for separating knapsack cuts */
184    int                   sepacardfreq;       /**< multiplier on separation frequency, how often knapsack cuts are separated */
185    int                   maxrounds;          /**< maximal number of separation rounds per node (-1: unlimited) */
186    int                   maxroundsroot;      /**< maximal number of separation rounds in the root node (-1: unlimited) */
187    int                   maxsepacuts;        /**< maximal number of cuts separated per separation round */
188    int                   maxsepacutsroot;    /**< maximal number of cuts separated per separation round in the root node */
189    SCIP_Bool             disaggregation;     /**< should disaggregation of knapsack constraints be allowed in preprocessing? */
190    SCIP_Bool             simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
191    SCIP_Bool             negatedclique;      /**< should negated clique information be used in solving process */
192    SCIP_Bool             presolpairwise;     /**< should pairwise constraint comparison be performed in presolving? */
193    SCIP_Bool             presolusehashing;   /**< should hash table be used for detecting redundant constraints in advance */
194    SCIP_Bool             dualpresolving;     /**< should dual presolving steps be performed? */
195    SCIP_Bool             usegubs;            /**< should GUB information be used for separation? */
196    SCIP_Bool             detectcutoffbound;  /**< should presolving try to detect constraints parallel to the objective
197                                               *   function defining an upper bound and prevent these constraints from
198                                               *   entering the LP */
199    SCIP_Bool             detectlowerbound;   /**< should presolving try to detect constraints parallel to the objective
200                                               *   function defining a lower bound and prevent these constraints from
201                                               *   entering the LP */
202    SCIP_Bool             updatecliquepartitions; /**< should clique partition information be updated when old partition seems outdated? */
203    SCIP_Real             cliqueextractfactor;/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
204    SCIP_Real             clqpartupdatefac;   /**< factor on the growth of global cliques to decide when to update a previous
205                                               *   (negated) clique partition (used only if updatecliquepartitions is set to TRUE) */
206 #ifdef WITH_CARDINALITY_UPGRADE
207    SCIP_Bool             upgdcardinality;    /**< if TRUE then try to update knapsack constraints to cardinality constraints */
208    SCIP_Bool             upgradedcard;       /**< whether we have already upgraded knapsack constraints to cardinality constraints */
209 #endif
210 };
211 
212 
213 /** constraint data for knapsack constraints */
214 struct SCIP_ConsData
215 {
216    SCIP_VAR**            vars;               /**< variables in knapsack constraint */
217    SCIP_Longint*         weights;            /**< weights of variables in knapsack constraint */
218    SCIP_EVENTDATA**      eventdata;          /**< event data for bound change events of the variables */
219    int*                  cliquepartition;    /**< clique indices of the clique partition */
220    int*                  negcliquepartition; /**< clique indices of the negated clique partition */
221    SCIP_ROW*             row;                /**< corresponding LP row */
222    int                   nvars;              /**< number of variables in knapsack constraint */
223    int                   varssize;           /**< size of vars, weights, and eventdata arrays */
224    int                   ncliques;           /**< number of cliques in the clique partition */
225    int                   nnegcliques;        /**< number of cliques in the negated clique partition */
226    int                   ncliqueslastnegpart;/**< number of global cliques the last time a negated clique partition was computed */
227    int                   ncliqueslastpart;   /**< number of global cliques the last time a clique partition was computed */
228    SCIP_Longint          capacity;           /**< capacity of knapsack */
229    SCIP_Longint          weightsum;          /**< sum of all weights */
230    SCIP_Longint          onesweightsum;      /**< sum of weights of variables fixed to one */
231    unsigned int          presolvedtiming:5;  /**< max level in which the knapsack constraint is already presolved */
232    unsigned int          sorted:1;           /**< are the knapsack items sorted by weight? */
233    unsigned int          cliquepartitioned:1;/**< is the clique partition valid? */
234    unsigned int          negcliquepartitioned:1;/**< is the negated clique partition valid? */
235    unsigned int          merged:1;           /**< are the constraint's equal variables already merged? */
236    unsigned int          cliquesadded:1;     /**< were the cliques of the knapsack already added to clique table? */
237    unsigned int          varsdeleted:1;      /**< were variables deleted after last cleanup? */
238    unsigned int          existmultaggr:1;    /**< does this constraint contain multi-aggregations */
239 };
240 
241 /** event data for bound changes events */
242 struct SCIP_EventData
243 {
244    SCIP_CONS*            cons;               /**< knapsack constraint to process the bound change for */
245    SCIP_Longint          weight;             /**< weight of variable */
246    int                   filterpos;          /**< position of event in variable's event filter */
247 };
248 
249 
250 /** data structure to combine two sorting key values */
251 struct sortkeypair
252 {
253    SCIP_Real             key1;               /**< first sort key value */
254    SCIP_Real             key2;               /**< second sort key value */
255 };
256 typedef struct sortkeypair SORTKEYPAIR;
257 
258 /** status of GUB constraint */
259 enum GUBVarstatus
260 {
261    GUBVARSTATUS_UNINITIAL        = -1,       /** unintitialized variable status */
262    GUBVARSTATUS_CAPACITYEXCEEDED =  0,       /** variable with weight exceeding the knapsack capacity */
263    GUBVARSTATUS_BELONGSTOSET_R   =  1,       /** variable in noncovervars R */
264    GUBVARSTATUS_BELONGSTOSET_F   =  2,       /** variable in noncovervars F */
265    GUBVARSTATUS_BELONGSTOSET_C2  =  3,       /** variable in covervars C2 */
266    GUBVARSTATUS_BELONGSTOSET_C1  =  4        /** variable in covervars C1 */
267 };
268 typedef enum GUBVarstatus GUBVARSTATUS;
269 
270 /** status of variable in GUB constraint */
271 enum GUBConsstatus
272 {
273    GUBCONSSTATUS_UNINITIAL         = -1,     /** unintitialized GUB constraint status */
274    GUBCONSSTATUS_BELONGSTOSET_GR   =  0,     /** all GUB variables are in noncovervars R */
275    GUBCONSSTATUS_BELONGSTOSET_GF   =  1,     /** all GUB variables are in noncovervars F (and noncovervars R) */
276    GUBCONSSTATUS_BELONGSTOSET_GC2  =  2,     /** all GUB variables are in covervars C2 */
277    GUBCONSSTATUS_BELONGSTOSET_GNC1 =  3,     /** some GUB variables are in covervars C1, others in noncovervars R or F */
278    GUBCONSSTATUS_BELONGSTOSET_GOC1 =  4      /** all GUB variables are in covervars C1 */
279 };
280 typedef enum GUBConsstatus GUBCONSSTATUS;
281 
282 /** data structure of GUB constraints */
283 struct SCIP_GUBCons
284 {
285    int*                  gubvars;            /**< indices of GUB variables in knapsack constraint */
286    GUBVARSTATUS*         gubvarsstatus;      /**< status of GUB variables */
287    int                   ngubvars;           /**< number of GUB variables */
288    int                   gubvarssize;        /**< size of gubvars array */
289 };
290 typedef struct SCIP_GUBCons SCIP_GUBCONS;
291 
292 /** data structure of a set of GUB constraints */
293 struct SCIP_GUBSet
294 {
295    SCIP_GUBCONS**        gubconss;           /**< GUB constraints in GUB set */
296    GUBCONSSTATUS*        gubconsstatus;      /**< status of GUB constraints */
297    int                   ngubconss;          /**< number of GUB constraints */
298    int                   nvars;              /**< number of variables in knapsack constraint */
299    int*                  gubconssidx;        /**< index of GUB constraint (in gubconss array) of each knapsack variable */
300    int*                  gubvarsidx;         /**< index in GUB constraint (in gubvars array) of each knapsack variable  */
301 };
302 typedef struct SCIP_GUBSet SCIP_GUBSET;
303 
304 /*
305  * Local methods
306  */
307 
308 /** comparison method for two sorting key pairs */
309 static
SCIP_DECL_SORTPTRCOMP(compSortkeypairs)310 SCIP_DECL_SORTPTRCOMP(compSortkeypairs)
311 {
312    SORTKEYPAIR* sortkeypair1 = (SORTKEYPAIR*)elem1;
313    SORTKEYPAIR* sortkeypair2 = (SORTKEYPAIR*)elem2;
314 
315    if( sortkeypair1->key1 < sortkeypair2->key1 )
316       return -1;
317    else if( sortkeypair1->key1 > sortkeypair2->key1 )
318       return +1;
319    else if( sortkeypair1->key2 < sortkeypair2->key2 )
320       return -1;
321    else if( sortkeypair1->key2 > sortkeypair2->key2 )
322       return +1;
323    else
324       return 0;
325 }
326 
327 /** creates event data */
328 static
eventdataCreate(SCIP * scip,SCIP_EVENTDATA ** eventdata,SCIP_CONS * cons,SCIP_Longint weight)329 SCIP_RETCODE eventdataCreate(
330    SCIP*                 scip,               /**< SCIP data structure */
331    SCIP_EVENTDATA**      eventdata,          /**< pointer to store event data */
332    SCIP_CONS*            cons,               /**< constraint */
333    SCIP_Longint          weight              /**< weight of variable */
334    )
335 {
336    assert(eventdata != NULL);
337 
338    SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
339    (*eventdata)->cons = cons;
340    (*eventdata)->weight = weight;
341 
342    return SCIP_OKAY;
343 }
344 
345 /** frees event data */
346 static
eventdataFree(SCIP * scip,SCIP_EVENTDATA ** eventdata)347 SCIP_RETCODE eventdataFree(
348    SCIP*                 scip,               /**< SCIP data structure */
349    SCIP_EVENTDATA**      eventdata           /**< pointer to event data */
350    )
351 {
352    assert(eventdata != NULL);
353 
354    SCIPfreeBlockMemory(scip, eventdata);
355 
356    return SCIP_OKAY;
357 }
358 
359 /** sorts items in knapsack with nonincreasing weights */
360 static
sortItems(SCIP_CONSDATA * consdata)361 void sortItems(
362    SCIP_CONSDATA*        consdata            /**< constraint data */
363    )
364 {
365    assert(consdata != NULL);
366    assert(consdata->nvars == 0 || consdata->vars != NULL);
367    assert(consdata->nvars == 0 || consdata->weights != NULL);
368    assert(consdata->nvars == 0 || consdata->eventdata != NULL);
369    assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
370 
371    if( !consdata->sorted )
372    {
373       int pos;
374       int lastcliquenum;
375       int v;
376 
377       /* sort of five joint arrays of Long/pointer/pointer/ints/ints,
378        * sorted by first array in non-increasing order via sort template */
379       SCIPsortDownLongPtrPtrIntInt(
380          consdata->weights,
381          (void**)consdata->vars,
382          (void**)consdata->eventdata,
383          consdata->cliquepartition,
384          consdata->negcliquepartition,
385          consdata->nvars);
386 
387       v = consdata->nvars - 1;
388       /* sort all items with same weight according to their variable index, used for hash value for fast pairwise comparison of all constraints */
389       while( v >= 0 )
390       {
391          int w = v - 1;
392 
393          while( w >= 0 && consdata->weights[v] == consdata->weights[w] )
394             --w;
395 
396          if( v - w > 1 )
397          {
398             /* sort all corresponding parts of arrays for which the weights are equal by using the variable index */
399             SCIPsortPtrPtrIntInt(
400                (void**)(&(consdata->vars[w+1])),
401                (void**)(&(consdata->eventdata[w+1])),
402                &(consdata->cliquepartition[w+1]),
403                &(consdata->negcliquepartition[w+1]),
404                SCIPvarComp,
405                v - w);
406          }
407          v = w;
408       }
409 
410       /* we need to make sure that our clique numbers of our normal clique will be in increasing order without gaps */
411       if( consdata->cliquepartitioned )
412       {
413          lastcliquenum = 0;
414 
415          for( pos = 0; pos < consdata->nvars; ++pos )
416          {
417             /* if the clique number in the normal clique at position pos is greater than the last found clique number the
418              * partition is invalid */
419             if( consdata->cliquepartition[pos] > lastcliquenum )
420             {
421                consdata->cliquepartitioned = FALSE;
422                break;
423             }
424             else if( consdata->cliquepartition[pos] == lastcliquenum )
425                ++lastcliquenum;
426          }
427       }
428       /* we need to make sure that our clique numbers of our negated clique will be in increasing order without gaps */
429       if( consdata->negcliquepartitioned )
430       {
431          lastcliquenum = 0;
432 
433          for( pos = 0; pos < consdata->nvars; ++pos )
434          {
435             /* if the clique number in the negated clique at position pos is greater than the last found clique number the
436              * partition is invalid */
437             if( consdata->negcliquepartition[pos] > lastcliquenum )
438             {
439                consdata->negcliquepartitioned = FALSE;
440                break;
441             }
442             else if( consdata->negcliquepartition[pos] == lastcliquenum )
443                ++lastcliquenum;
444          }
445       }
446 
447       consdata->sorted = TRUE;
448    }
449 #ifndef NDEBUG
450    {
451       /* check if the weight array is sorted in a non-increasing way */
452       int i;
453       for( i = 0; i < consdata->nvars-1; ++i )
454          assert(consdata->weights[i] >= consdata->weights[i+1]);
455    }
456 #endif
457 }
458 
459 /** calculates a partition of the variables into cliques */
460 static
calcCliquepartition(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONSDATA * consdata,SCIP_Bool normalclique,SCIP_Bool negatedclique)461 SCIP_RETCODE calcCliquepartition(
462    SCIP*                 scip,               /**< SCIP data structure */
463    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< knapsack constraint handler data */
464    SCIP_CONSDATA*        consdata,           /**< constraint data */
465    SCIP_Bool             normalclique,       /**< Should normal cliquepartition be created? */
466    SCIP_Bool             negatedclique       /**< Should negated cliquepartition be created? */
467    )
468 {
469    SCIP_Bool ispartitionoutdated;
470    SCIP_Bool isnegpartitionoutdated;
471    assert(consdata != NULL);
472    assert(consdata->nvars == 0 || (consdata->cliquepartition != NULL && consdata->negcliquepartition != NULL));
473 
474    /* rerun eventually if number of global cliques increased considerably since last partition */
475    ispartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->ncliques > 1
476          && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastpart));
477 
478    if( normalclique && ( !consdata->cliquepartitioned || ispartitionoutdated ) )
479    {
480       SCIP_CALL( SCIPcalcCliquePartition(scip, consdata->vars, consdata->nvars, consdata->cliquepartition, &consdata->ncliques) );
481       consdata->cliquepartitioned = TRUE;
482       consdata->ncliqueslastpart = SCIPgetNCliques(scip);
483    }
484 
485    /* rerun eventually if number of global cliques increased considerably since last negated partition */
486    isnegpartitionoutdated = (conshdlrdata->updatecliquepartitions && consdata->nnegcliques > 1
487          && SCIPgetNCliques(scip) >= (int)(conshdlrdata->clqpartupdatefac * consdata->ncliqueslastnegpart));
488 
489    if( negatedclique && (!consdata->negcliquepartitioned || isnegpartitionoutdated) )
490    {
491       SCIP_CALL( SCIPcalcNegatedCliquePartition(scip, consdata->vars, consdata->nvars, consdata->negcliquepartition, &consdata->nnegcliques) );
492       consdata->negcliquepartitioned = TRUE;
493       consdata->ncliqueslastnegpart = SCIPgetNCliques(scip);
494    }
495    assert(!consdata->cliquepartitioned || consdata->ncliques <= consdata->nvars);
496    assert(!consdata->negcliquepartitioned || consdata->nnegcliques <= consdata->nvars);
497 
498    return SCIP_OKAY;
499 }
500 
501 /** installs rounding locks for the given variable in the given knapsack constraint */
502 static
lockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)503 SCIP_RETCODE lockRounding(
504    SCIP*                 scip,               /**< SCIP data structure */
505    SCIP_CONS*            cons,               /**< knapsack constraint */
506    SCIP_VAR*             var                 /**< variable of constraint entry */
507    )
508 {
509    SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
510 
511    return SCIP_OKAY;
512 }
513 
514 /** removes rounding locks for the given variable in the given knapsack constraint */
515 static
unlockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)516 SCIP_RETCODE unlockRounding(
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( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
523 
524    return SCIP_OKAY;
525 }
526 
527 /** catches bound change events for variables in knapsack */
528 static
catchEvents(SCIP * scip,SCIP_CONS * cons,SCIP_CONSDATA * consdata,SCIP_EVENTHDLR * eventhdlr)529 SCIP_RETCODE catchEvents(
530    SCIP*                 scip,               /**< SCIP data structure */
531    SCIP_CONS*            cons,               /**< constraint */
532    SCIP_CONSDATA*        consdata,           /**< constraint data */
533    SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
534    )
535 {
536    int i;
537 
538    assert(cons != NULL);
539    assert(consdata != NULL);
540    assert(consdata->nvars == 0 || consdata->vars != NULL);
541    assert(consdata->nvars == 0 || consdata->weights != NULL);
542    assert(consdata->nvars == 0 || consdata->eventdata != NULL);
543 
544    for( i = 0; i < consdata->nvars; i++)
545    {
546       SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[i], cons, consdata->weights[i]) );
547       SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
548             eventhdlr, consdata->eventdata[i], &consdata->eventdata[i]->filterpos) );
549    }
550 
551    return SCIP_OKAY;
552 }
553 
554 /** drops bound change events for variables in knapsack */
555 static
dropEvents(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_EVENTHDLR * eventhdlr)556 SCIP_RETCODE dropEvents(
557    SCIP*                 scip,               /**< SCIP data structure */
558    SCIP_CONSDATA*        consdata,           /**< constraint data */
559    SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
560    )
561 {
562    int i;
563 
564    assert(consdata != NULL);
565    assert(consdata->nvars == 0 || consdata->vars != NULL);
566    assert(consdata->nvars == 0 || consdata->weights != NULL);
567    assert(consdata->nvars == 0 || consdata->eventdata != NULL);
568 
569    for( i = 0; i < consdata->nvars; i++)
570    {
571       SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], EVENTTYPE_KNAPSACK,
572             eventhdlr, consdata->eventdata[i], consdata->eventdata[i]->filterpos) );
573       SCIP_CALL( eventdataFree(scip, &consdata->eventdata[i]) );
574    }
575 
576    return SCIP_OKAY;
577 }
578 
579 /** ensures, that vars and vals arrays can store at least num entries */
580 static
consdataEnsureVarsSize(SCIP * scip,SCIP_CONSDATA * consdata,int num,SCIP_Bool transformed)581 SCIP_RETCODE consdataEnsureVarsSize(
582    SCIP*                 scip,               /**< SCIP data structure */
583    SCIP_CONSDATA*        consdata,           /**< knapsack constraint data */
584    int                   num,                /**< minimum number of entries to store */
585    SCIP_Bool             transformed         /**< is constraint from transformed problem? */
586    )
587 {
588    assert(consdata != NULL);
589    assert(consdata->nvars <= consdata->varssize);
590 
591    if( num > consdata->varssize )
592    {
593       int newsize;
594 
595       newsize = SCIPcalcMemGrowSize(scip, num);
596       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
597       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->varssize, newsize) );
598       if( transformed )
599       {
600          SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
601          SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->cliquepartition, consdata->varssize, newsize) );
602          SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->negcliquepartition, consdata->varssize, newsize) );
603       }
604       else
605       {
606          assert(consdata->eventdata == NULL);
607          assert(consdata->cliquepartition == NULL);
608          assert(consdata->negcliquepartition == NULL);
609       }
610       consdata->varssize = newsize;
611    }
612    assert(num <= consdata->varssize);
613 
614    return SCIP_OKAY;
615 }
616 
617 /** updates all weight sums for fixed and unfixed variables */
618 static
updateWeightSums(SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Longint weightdelta)619 void updateWeightSums(
620    SCIP_CONSDATA*        consdata,           /**< knapsack constraint data */
621    SCIP_VAR*             var,                /**< variable for this weight */
622    SCIP_Longint          weightdelta         /**< difference between the old and the new weight of the variable */
623    )
624 {
625    assert(consdata != NULL);
626    assert(var != NULL);
627 
628    consdata->weightsum += weightdelta;
629 
630    if( SCIPvarGetLbLocal(var) > 0.5 )
631       consdata->onesweightsum += weightdelta;
632 
633    assert(consdata->weightsum >= 0);
634    assert(consdata->onesweightsum >= 0);
635 }
636 
637 /** creates knapsack constraint data */
638 static
consdataCreate(SCIP * scip,SCIP_CONSDATA ** consdata,int nvars,SCIP_VAR ** vars,SCIP_Longint * weights,SCIP_Longint capacity)639 SCIP_RETCODE consdataCreate(
640    SCIP*                 scip,               /**< SCIP data structure */
641    SCIP_CONSDATA**       consdata,           /**< pointer to store constraint data */
642    int                   nvars,              /**< number of variables in knapsack */
643    SCIP_VAR**            vars,               /**< variables of knapsack */
644    SCIP_Longint*         weights,            /**< weights of knapsack items */
645    SCIP_Longint          capacity            /**< capacity of knapsack */
646    )
647 {
648    int v;
649    SCIP_Longint constant;
650 
651    assert(consdata != NULL);
652 
653    SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
654 
655    constant = 0L;
656    (*consdata)->vars = NULL;
657    (*consdata)->weights = NULL;
658    (*consdata)->nvars = 0;
659    if( nvars > 0 )
660    {
661       SCIP_VAR** varsbuffer;
662       SCIP_Longint* weightsbuffer;
663       int k;
664 
665       SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
666       SCIP_CALL( SCIPallocBufferArray(scip, &weightsbuffer, nvars) );
667 
668       k = 0;
669       for( v = 0; v < nvars; ++v )
670       {
671          assert(vars[v] != NULL);
672          assert(SCIPvarIsBinary(vars[v]));
673 
674          /* all weight have to be non negative */
675          assert( weights[v] >= 0 );
676 
677          if( weights[v] > 0 )
678          {
679             /* treat fixed variables as constants if problem compression is enabled */
680             if( SCIPisConsCompressionEnabled(scip) && SCIPvarGetLbGlobal(vars[v]) > SCIPvarGetUbGlobal(vars[v]) - 0.5 )
681             {
682                /* only if the variable is fixed to 1, we add its weight to the constant */
683                if( SCIPvarGetUbGlobal(vars[v]) > 0.5 )
684                   constant += weights[v];
685             }
686             else
687             {
688                varsbuffer[k] = vars[v];
689                weightsbuffer[k] = weights[v];
690                ++k;
691             }
692          }
693       }
694       assert(k >= 0);
695 
696       (*consdata)->nvars = k;
697 
698       /* copy the active variables and weights into the constraint data structure */
699       if( k > 0 )
700       {
701          SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
702          SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->weights, weightsbuffer, k) );
703       }
704 
705       /* free buffer storage */
706       SCIPfreeBufferArray(scip, &weightsbuffer);
707       SCIPfreeBufferArray(scip, &varsbuffer);
708    }
709 
710    /* capacity has to be greater or equal to zero */
711    assert(capacity >= 0);
712    assert(constant >= 0);
713 
714    (*consdata)->varssize = (*consdata)->nvars;
715    (*consdata)->capacity = capacity - constant;
716    (*consdata)->eventdata = NULL;
717    (*consdata)->cliquepartition = NULL;
718    (*consdata)->negcliquepartition = NULL;
719    (*consdata)->row = NULL;
720    (*consdata)->weightsum = 0;
721    (*consdata)->onesweightsum = 0;
722    (*consdata)->ncliques = 0;
723    (*consdata)->nnegcliques = 0;
724    (*consdata)->presolvedtiming = 0;
725    (*consdata)->sorted = FALSE;
726    (*consdata)->cliquepartitioned = FALSE;
727    (*consdata)->negcliquepartitioned = FALSE;
728    (*consdata)->ncliqueslastpart = -1;
729    (*consdata)->ncliqueslastnegpart = -1;
730    (*consdata)->merged = FALSE;
731    (*consdata)->cliquesadded = FALSE;
732    (*consdata)->varsdeleted = FALSE;
733    (*consdata)->existmultaggr = FALSE;
734 
735    /* get transformed variables, if we are in the transformed problem */
736    if( SCIPisTransformed(scip) )
737    {
738       SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
739 
740       for( v = 0; v < (*consdata)->nvars; v++ )
741       {
742          SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
743          assert(var != NULL);
744          (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
745       }
746 
747       /* allocate memory for additional data structures */
748       SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->nvars) );
749       SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->nvars) );
750       SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->nvars) );
751    }
752 
753    /* calculate sum of weights and capture variables */
754    for( v = 0; v < (*consdata)->nvars; ++v )
755    {
756       /* calculate sum of weights */
757       updateWeightSums(*consdata, (*consdata)->vars[v], (*consdata)->weights[v]);
758 
759       /* capture variables */
760       SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
761    }
762    return SCIP_OKAY;
763 }
764 
765 /** frees knapsack constraint data */
766 static
consdataFree(SCIP * scip,SCIP_CONSDATA ** consdata,SCIP_EVENTHDLR * eventhdlr)767 SCIP_RETCODE consdataFree(
768    SCIP*                 scip,               /**< SCIP data structure */
769    SCIP_CONSDATA**       consdata,           /**< pointer to the constraint data */
770    SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
771    )
772 {
773    assert(consdata != NULL);
774    assert(*consdata != NULL);
775 
776    if( (*consdata)->row != NULL )
777    {
778       SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
779    }
780    if( (*consdata)->eventdata != NULL )
781    {
782       SCIP_CALL( dropEvents(scip, *consdata, eventhdlr) );
783       SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdata, (*consdata)->varssize);
784    }
785    if( (*consdata)->negcliquepartition != NULL )
786    {
787       SCIPfreeBlockMemoryArray(scip, &(*consdata)->negcliquepartition, (*consdata)->varssize);
788    }
789    if( (*consdata)->cliquepartition != NULL )
790    {
791       SCIPfreeBlockMemoryArray(scip, &(*consdata)->cliquepartition, (*consdata)->varssize);
792    }
793    if( (*consdata)->vars != NULL )
794    {
795       int v;
796 
797       /* release variables */
798       for( v = 0; v < (*consdata)->nvars; v++ )
799       {
800          assert((*consdata)->vars[v] != NULL);
801          SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
802       }
803 
804       assert( (*consdata)->weights != NULL );
805       assert( (*consdata)->varssize > 0 );
806       SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
807       SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->varssize);
808    }
809 
810    SCIPfreeBlockMemory(scip, consdata);
811 
812    return SCIP_OKAY;
813 }
814 
815 /** changes a single weight in knapsack constraint data */
816 static
consdataChgWeight(SCIP_CONSDATA * consdata,int item,SCIP_Longint newweight)817 void consdataChgWeight(
818    SCIP_CONSDATA*        consdata,           /**< knapsack constraint data */
819    int                   item,               /**< item number */
820    SCIP_Longint          newweight           /**< new weight of item */
821    )
822 {
823    SCIP_Longint oldweight;
824    SCIP_Longint weightdiff;
825 
826    assert(consdata != NULL);
827    assert(0 <= item && item < consdata->nvars);
828 
829    oldweight = consdata->weights[item];
830    weightdiff = newweight - oldweight;
831    consdata->weights[item] = newweight;
832 
833    /* update weight sums for all and fixed variables */
834    updateWeightSums(consdata, consdata->vars[item], weightdiff);
835 
836    if( consdata->eventdata != NULL )
837    {
838       assert(consdata->eventdata[item] != NULL);
839       assert(consdata->eventdata[item]->weight == oldweight);
840       consdata->eventdata[item]->weight = newweight;
841    }
842 
843    consdata->presolvedtiming = 0;
844    consdata->sorted = FALSE;
845 
846    /* recalculate cliques extraction after a weight was increased */
847    if( oldweight < newweight )
848    {
849       consdata->cliquesadded = FALSE;
850    }
851 }
852 
853 /** creates LP row corresponding to knapsack constraint */
854 static
createRelaxation(SCIP * scip,SCIP_CONS * cons)855 SCIP_RETCODE createRelaxation(
856    SCIP*                 scip,               /**< SCIP data structure */
857    SCIP_CONS*            cons                /**< knapsack constraint */
858    )
859 {
860    SCIP_CONSDATA* consdata;
861    int i;
862 
863    consdata = SCIPconsGetData(cons);
864    assert(consdata != NULL);
865    assert(consdata->row == NULL);
866 
867    SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons),
868          -SCIPinfinity(scip), (SCIP_Real)consdata->capacity,
869          SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) );
870 
871    SCIP_CALL( SCIPcacheRowExtensions(scip, consdata->row) );
872    for( i = 0; i < consdata->nvars; ++i )
873    {
874       SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, consdata->vars[i], (SCIP_Real)consdata->weights[i]) );
875    }
876    SCIP_CALL( SCIPflushRowExtensions(scip, consdata->row) );
877 
878    return SCIP_OKAY;
879 }
880 
881 /** adds linear relaxation of knapsack constraint to the LP */
882 static
addRelaxation(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff)883 SCIP_RETCODE addRelaxation(
884    SCIP*                 scip,               /**< SCIP data structure */
885    SCIP_CONS*            cons,               /**< knapsack constraint */
886    SCIP_Bool*            cutoff              /**< whether a cutoff has been detected */
887    )
888 {
889    SCIP_CONSDATA* consdata;
890 
891    assert( cutoff != NULL );
892    *cutoff = FALSE;
893 
894    consdata = SCIPconsGetData(cons);
895    assert(consdata != NULL);
896 
897    if( consdata->row == NULL )
898    {
899       SCIP_CALL( createRelaxation(scip, cons) );
900    }
901    assert(consdata->row != NULL);
902 
903    /* insert LP row as cut */
904    if( !SCIProwIsInLP(consdata->row) )
905    {
906       SCIPdebugMsg(scip, "adding relaxation of knapsack constraint <%s> (capacity %" SCIP_LONGINT_FORMAT "): ",
907          SCIPconsGetName(cons), consdata->capacity);
908       SCIPdebug( SCIP_CALL(SCIPprintRow(scip, consdata->row, NULL)) );
909       SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
910    }
911 
912    return SCIP_OKAY;
913 }
914 
915 /** checks knapsack constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
916 static
checkCons(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol,SCIP_Bool checklprows,SCIP_Bool printreason,SCIP_Bool * violated)917 SCIP_RETCODE checkCons(
918    SCIP*                 scip,               /**< SCIP data structure */
919    SCIP_CONS*            cons,               /**< constraint to check */
920    SCIP_SOL*             sol,                /**< solution to check, NULL for current solution */
921    SCIP_Bool             checklprows,        /**< Do constraints represented by rows in the current LP have to be checked? */
922    SCIP_Bool             printreason,        /**< Should the reason for the violation be printed? */
923    SCIP_Bool*            violated            /**< pointer to store whether the constraint is violated */
924    )
925 {
926    SCIP_CONSDATA* consdata;
927 
928    assert(violated != NULL);
929 
930    consdata = SCIPconsGetData(cons);
931    assert(consdata != NULL);
932 
933    SCIPdebugMsg(scip, "checking knapsack constraint <%s> for feasibility of solution %p (lprows=%u)\n",
934       SCIPconsGetName(cons), (void*)sol, checklprows);
935 
936    *violated = FALSE;
937 
938    if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
939    {
940       SCIP_Real sum;
941       SCIP_Longint integralsum;
942       SCIP_Bool ishuge;
943       SCIP_Real absviol;
944       SCIP_Real relviol;
945       int v;
946 
947       /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
948        * enforcement
949        */
950       if( sol == NULL )
951       {
952          SCIP_CALL( SCIPincConsAge(scip, cons) );
953       }
954 
955       sum = 0.0;
956       integralsum = 0;
957       /* we perform a more exact comparison if the capacity does not exceed the huge value */
958       if( SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
959       {
960          ishuge = TRUE;
961 
962          /* sum over all weight times the corresponding solution value */
963          for( v = consdata->nvars - 1; v >= 0; --v )
964          {
965             assert(SCIPvarIsBinary(consdata->vars[v]));
966             sum += consdata->weights[v] * SCIPgetSolVal(scip, sol, consdata->vars[v]);
967          }
968       }
969       else
970       {
971          ishuge = FALSE;
972 
973          /* sum over all weight for which the variable has a solution value of 1 in feastol */
974          for( v = consdata->nvars - 1; v >= 0; --v )
975          {
976             assert(SCIPvarIsBinary(consdata->vars[v]));
977 
978             if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
979                integralsum += consdata->weights[v];
980          }
981       }
982 
983       /* calculate constraint violation and update it in solution */
984       absviol = ishuge ? sum : (SCIP_Real)integralsum;
985       absviol -= consdata->capacity;
986       relviol = SCIPrelDiff(absviol + consdata->capacity, (SCIP_Real)consdata->capacity);
987       if( sol != NULL )
988          SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
989 
990       if( SCIPisFeasPositive(scip, absviol) )
991       {
992          *violated = TRUE;
993 
994          /* only reset constraint age if we are in enforcement */
995          if( sol == NULL )
996          {
997             SCIP_CALL( SCIPresetConsAge(scip, cons) );
998          }
999 
1000          if( printreason )
1001          {
1002             SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1003 
1004             SCIPinfoMessage(scip, NULL, ";\n");
1005             SCIPinfoMessage(scip, NULL, "violation: the capacity is violated by %.15g\n", absviol);
1006          }
1007       }
1008    }
1009 
1010    return SCIP_OKAY;
1011 }
1012 
1013 /* IDX computes the integer index for the optimal solution array */
1014 #define IDX(j,d) ((j)*(intcap)+(d))
1015 
1016 /** solves knapsack problem in maximization form exactly using dynamic programming;
1017  *  if needed, one can provide arrays to store all selected items and all not selected items
1018  *
1019  * @note in case you provide the solitems or nonsolitems array you also have to provide the counter part, as well
1020  *
1021  * @note the algorithm will first compute a greedy solution and terminate
1022  *       if the greedy solution is proven to be optimal.
1023  *       The dynamic programming algorithm runs with a time and space complexity
1024  *       of O(nitems * capacity).
1025  *
1026  * @todo If only the objective is relevant, it is easy to change the code to use only one slice with O(capacity) space.
1027  *       There are recursive methods (see the book by Kellerer et al.) that require O(capacity) space, but it remains
1028  *       to be checked whether they are faster and whether they can reconstruct the solution.
1029  *       Dembo and Hammer (see Kellerer et al. Section 5.1.3, page 126) found a method that relies on a fast probing method.
1030  *       This fixes additional elements to 0 or 1 similar to a reduced cost fixing.
1031  *       This could be implemented, however, it would be technically a bit cumbersome,
1032  *       since one needs the greedy solution and the LP-value for this.
1033  *       This is currently only available after the redundant items have already been sorted out.
1034  */
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)1035 SCIP_RETCODE SCIPsolveKnapsackExactly(
1036    SCIP*                 scip,               /**< SCIP data structure */
1037    int                   nitems,             /**< number of available items */
1038    SCIP_Longint*         weights,            /**< item weights */
1039    SCIP_Real*            profits,            /**< item profits */
1040    SCIP_Longint          capacity,           /**< capacity of knapsack */
1041    int*                  items,              /**< item numbers */
1042    int*                  solitems,           /**< array to store items in solution, or NULL */
1043    int*                  nonsolitems,        /**< array to store items not in solution, or NULL */
1044    int*                  nsolitems,          /**< pointer to store number of items in solution, or NULL */
1045    int*                  nnonsolitems,       /**< pointer to store number of items not in solution, or NULL */
1046    SCIP_Real*            solval,             /**< pointer to store optimal solution value, or NULL */
1047    SCIP_Bool*            success             /**< pointer to store if an error occured during solving
1048                                               *   (normally a memory problem) */
1049    )
1050 {
1051    SCIP_RETCODE retcode;
1052    SCIP_Real* tempsort;
1053    SCIP_Real* optvalues;
1054    int intcap;
1055    int d;
1056    int j;
1057    int greedymedianpos;
1058    SCIP_Longint weightsum;
1059    int* myitems;
1060    SCIP_Longint* myweights;
1061    SCIP_Real* realweights;
1062    int* allcurrminweight;
1063    SCIP_Real* myprofits;
1064    int nmyitems;
1065    SCIP_Longint gcd;
1066    SCIP_Longint minweight;
1067    SCIP_Longint maxweight;
1068    int currminweight;
1069    SCIP_Longint greedysolweight;
1070    SCIP_Real greedysolvalue;
1071    SCIP_Real greedyupperbound;
1072    SCIP_Bool eqweights;
1073    SCIP_Bool intprofits;
1074 
1075    assert(weights != NULL);
1076    assert(profits != NULL);
1077    assert(capacity >= 0);
1078    assert(items != NULL);
1079    assert(nitems >= 0);
1080    assert(success != NULL);
1081 
1082    *success = TRUE;
1083 
1084 #ifndef NDEBUG
1085    for( j = nitems - 1; j >= 0; --j )
1086       assert(weights[j] >= 0);
1087 #endif
1088 
1089    SCIPdebugMsg(scip, "Solving knapsack exactly.\n");
1090 
1091    /* initializing solution value */
1092    if( solval != NULL )
1093       *solval = 0.0;
1094 
1095    /* init solution information */
1096    if( solitems != NULL )
1097    {
1098       assert(items != NULL);
1099       assert(nsolitems != NULL);
1100       assert(nonsolitems != NULL);
1101       assert(nnonsolitems != NULL);
1102 
1103       *nnonsolitems = 0;
1104       *nsolitems = 0;
1105    }
1106 
1107    /* allocate temporary memory */
1108    SCIP_CALL( SCIPallocBufferArray(scip, &myweights, nitems) );
1109    SCIP_CALL( SCIPallocBufferArray(scip, &myprofits, nitems) );
1110    SCIP_CALL( SCIPallocBufferArray(scip, &myitems, nitems) );
1111    nmyitems = 0;
1112    weightsum = 0;
1113    minweight = SCIP_LONGINT_MAX;
1114    maxweight = 0;
1115 
1116    /* remove unnecessary items */
1117    for( j = 0; j < nitems; ++j )
1118    {
1119       assert(0 <= weights[j] && weights[j] < SCIP_LONGINT_MAX);
1120 
1121       /* item does not fit */
1122       if( weights[j] > capacity )
1123       {
1124          if( solitems != NULL )
1125             nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1126       }
1127       /* item is not profitable */
1128       else if( profits[j] <= 0.0 )
1129       {
1130          if( solitems != NULL )
1131             nonsolitems[(*nnonsolitems)++] = items[j]; /*lint !e413*/
1132       }
1133       /* item always fits */
1134       else if( weights[j] == 0 )
1135       {
1136          if( solitems != NULL )
1137             solitems[(*nsolitems)++] = items[j]; /*lint !e413*/
1138 
1139          if( solval != NULL )
1140             *solval += profits[j];
1141       }
1142       /* all important items */
1143       else
1144       {
1145          myweights[nmyitems] = weights[j];
1146          myprofits[nmyitems] = profits[j];
1147          myitems[nmyitems] = items[j];
1148 
1149          /* remember smallest item */
1150          if( myweights[nmyitems] < minweight )
1151             minweight = myweights[nmyitems];
1152 
1153          /* remember bigest item */
1154          if( myweights[nmyitems] > maxweight )
1155             maxweight = myweights[nmyitems];
1156 
1157          weightsum += myweights[nmyitems];
1158          ++nmyitems;
1159       }
1160    }
1161 
1162    intprofits = TRUE;
1163    /* check if all profits are integer to strengthen the upper bound on the greedy solution */
1164    for( j = 0; j < nmyitems && intprofits; ++j )
1165       intprofits = intprofits && SCIPisIntegral(scip, myprofits[j]);
1166 
1167    /* if no item is left then goto end */
1168    if( nmyitems == 0 )
1169    {
1170       SCIPdebugMsg(scip, "After preprocessing no items are left.\n");
1171 
1172       goto TERMINATE;
1173    }
1174 
1175    /* if all items fit, we also do not need to do the expensive stuff later on */
1176    if( weightsum > 0 && weightsum <= capacity )
1177    {
1178       SCIPdebugMsg(scip, "After preprocessing all items fit into knapsack.\n");
1179 
1180       for( j = nmyitems - 1; j >= 0; --j )
1181       {
1182          if( solitems != NULL )
1183             solitems[(*nsolitems)++] = myitems[j]; /*lint !e413*/
1184 
1185          if( solval != NULL )
1186             *solval += myprofits[j];
1187       }
1188 
1189       goto TERMINATE;
1190    }
1191 
1192    assert(0 < minweight && minweight <= capacity );
1193    assert(0 < maxweight && maxweight <= capacity);
1194 
1195    /* make weights relatively prime */
1196    eqweights = TRUE;
1197    if( maxweight > 1 )
1198    {
1199       /* determine greatest common divisor */
1200       gcd = myweights[nmyitems - 1];
1201       for( j = nmyitems - 2; j >= 0 && gcd >= 2; --j )
1202          gcd = SCIPcalcGreComDiv(gcd, myweights[j]);
1203 
1204       SCIPdebugMsg(scip, "Gcd is %" SCIP_LONGINT_FORMAT ".\n", gcd);
1205 
1206       /* divide by greatest common divisor */
1207       if( gcd > 1 )
1208       {
1209          for( j = nmyitems - 1; j >= 0; --j )
1210          {
1211             myweights[j] /= gcd;
1212             eqweights = eqweights && (myweights[j] == 1);
1213          }
1214          capacity /= gcd;
1215          minweight /= gcd;
1216       }
1217       else
1218          eqweights = FALSE;
1219    }
1220    assert(minweight <= capacity);
1221 
1222    /* if only one item fits, then take the best */
1223    if( minweight > capacity / 2 )
1224    {
1225       int p;
1226 
1227       SCIPdebugMsg(scip, "Only one item fits into knapsack, so take the best.\n");
1228 
1229       p = nmyitems - 1;
1230 
1231       /* find best item */
1232       for( j = nmyitems - 2; j >= 0; --j )
1233       {
1234          if( myprofits[j] > myprofits[p] )
1235             p = j;
1236       }
1237 
1238       /* update solution information */
1239       if( solitems != NULL )
1240       {
1241          assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1242 
1243          solitems[(*nsolitems)++] = myitems[p];
1244          for( j = nmyitems - 1; j >= 0; --j )
1245          {
1246             if( j != p )
1247                nonsolitems[(*nnonsolitems)++] = myitems[j];
1248          }
1249       }
1250       /* update solution value */
1251       if( solval != NULL )
1252          *solval += myprofits[p];
1253 
1254       goto TERMINATE;
1255    }
1256 
1257    /* if all items have the same weight, then take the best */
1258    if( eqweights )
1259    {
1260       SCIP_Real addval = 0.0;
1261 
1262       SCIPdebugMsg(scip, "All weights are equal, so take the best.\n");
1263 
1264       SCIPsortDownRealIntLong(myprofits, myitems, myweights, nmyitems);
1265 
1266       /* update solution information */
1267       if( solitems != NULL || solval != NULL )
1268       {
1269          SCIP_Longint i;
1270 
1271          /* if all items would fit we had handled this case before */
1272          assert((SCIP_Longint) nmyitems > capacity);
1273          assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1274 
1275          /* take the first best items into the solution */
1276          for( i = capacity - 1; i >= 0; --i )
1277          {
1278             if( solitems != NULL )
1279                solitems[(*nsolitems)++] = myitems[i];
1280             addval += myprofits[i];
1281          }
1282 
1283          if( solitems != NULL )
1284          {
1285             /* the rest are not in the solution */
1286             for( i = nmyitems - 1; i >= capacity; --i )
1287                nonsolitems[(*nnonsolitems)++] = myitems[i];
1288          }
1289       }
1290       /* update solution value */
1291       if( solval != NULL )
1292       {
1293          assert(addval > 0.0);
1294          *solval += addval;
1295       }
1296 
1297       goto TERMINATE;
1298    }
1299 
1300    SCIPdebugMsg(scip, "Determine greedy solution.\n");
1301 
1302    /* sort myitems (plus corresponding arrays myweights and myprofits) such that
1303     * p_1/w_1 >= p_2/w_2 >= ... >= p_n/w_n, this is only used for the greedy solution
1304     */
1305    SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nmyitems) );
1306    SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nmyitems) );
1307 
1308    for( j = 0; j < nmyitems; ++j )
1309    {
1310       tempsort[j] = myprofits[j]/((SCIP_Real) myweights[j]);
1311       realweights[j] = (SCIP_Real)myweights[j];
1312    }
1313 
1314    SCIPselectWeightedDownRealLongRealInt(tempsort, myweights, myprofits, myitems, realweights,
1315       (SCIP_Real)capacity, nmyitems, &greedymedianpos);
1316 
1317    SCIPfreeBufferArray(scip, &realweights);
1318    SCIPfreeBufferArray(scip, &tempsort);
1319 
1320    /* initialize values for greedy solution information */
1321    greedysolweight = 0;
1322    greedysolvalue = 0.0;
1323 
1324    /* determine greedy solution */
1325    for( j = 0; j < greedymedianpos; ++j )
1326    {
1327       assert(myweights[j] <= capacity);
1328 
1329       /* update greedy solution weight and value */
1330       greedysolweight += myweights[j];
1331       greedysolvalue += myprofits[j];
1332    }
1333 
1334    assert(0 < greedysolweight && greedysolweight <= capacity);
1335    assert(greedysolvalue > 0.0);
1336 
1337    /* If the greedy solution is optimal by comparing to the LP solution, we take this solution. This happens if:
1338     * - the greedy solution reaches the capacity, because then the LP solution is integral;
1339     * - the greedy solution has an objective that is at least the LP value rounded down in case that all profits are integer, too. */
1340    greedyupperbound = greedysolvalue + myprofits[j] * (SCIP_Real) (capacity - greedysolweight)/((SCIP_Real) myweights[j]);
1341    if( intprofits )
1342       greedyupperbound = SCIPfloor(scip, greedyupperbound);
1343    if( greedysolweight == capacity || SCIPisGE(scip, greedysolvalue, greedyupperbound) )
1344    {
1345       SCIPdebugMsg(scip, "Greedy solution is optimal.\n");
1346 
1347       /* update solution information */
1348       if( solitems != NULL )
1349       {
1350          int l;
1351 
1352          assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1353 
1354          /* collect items */
1355          for( l = 0; l < j; ++l )
1356             solitems[(*nsolitems)++] = myitems[l];
1357          for ( ; l < nmyitems; ++l )
1358             nonsolitems[(*nnonsolitems)++] = myitems[l];
1359       }
1360       /* update solution value */
1361       if( solval != NULL )
1362       {
1363          assert(greedysolvalue > 0.0);
1364          *solval += greedysolvalue;
1365       }
1366 
1367       goto TERMINATE;
1368    }
1369 
1370    /* in the following table we do not need the first minweight columns */
1371    capacity -= (minweight - 1);
1372 
1373    /* we can only handle integers */
1374    if( capacity >= INT_MAX )
1375    {
1376       SCIPdebugMsg(scip, "Capacity is to big, so we cannot handle it here.\n");
1377 
1378       *success = FALSE;
1379       goto TERMINATE;
1380    }
1381    assert(capacity < INT_MAX);
1382 
1383    intcap = (int)capacity;
1384    assert(intcap >= 0);
1385    assert(nmyitems > 0);
1386    assert(sizeof(size_t) >= sizeof(int)); /*lint !e506*/ /* no following conversion should be messed up */
1387 
1388    /* this condition checks whether we will try to allocate a correct number of bytes and do not have an overflow, while
1389     * computing the size for the allocation
1390     */
1391    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*/
1392    {
1393       SCIPdebugMsg(scip, "Too much memory (%lu) would be consumed.\n", (unsigned long) (((size_t)nmyitems) * ((size_t)intcap) * sizeof(*optvalues))); /*lint !e571*/
1394 
1395       *success = FALSE;
1396       goto TERMINATE;
1397    }
1398 
1399    /* allocate temporary memory and check for memory exceedance */
1400    retcode = SCIPallocBufferArray(scip, &optvalues, nmyitems * intcap);
1401    if( retcode == SCIP_NOMEMORY )
1402    {
1403       SCIPdebugMsg(scip, "Did not get enough memory.\n");
1404 
1405       *success = FALSE;
1406       goto TERMINATE;
1407    }
1408    else
1409    {
1410       SCIP_CALL( retcode );
1411    }
1412 
1413    SCIPdebugMsg(scip, "Start real exact algorithm.\n");
1414 
1415    /* we memorize at each step the current minimal weight to later on know which value in our optvalues matrix is valid;
1416     * each value entries of the j-th row of optvalues is valid if the index is >= allcurrminweight[j], otherwise it is
1417     * invalid; a second possibility would be to clear the whole optvalues, which should be more expensive than storing
1418     * 'nmyitem' values
1419     */
1420    SCIP_CALL( SCIPallocBufferArray(scip, &allcurrminweight, nmyitems) );
1421    assert(myweights[0] - minweight < INT_MAX);
1422    currminweight = (int) (myweights[0] - minweight);
1423    allcurrminweight[0] = currminweight;
1424 
1425    /* fills first row of dynamic programming table with optimal values */
1426    for( d = currminweight; d < intcap; ++d )
1427       optvalues[d] = myprofits[0];
1428 
1429    /* fills dynamic programming table with optimal values */
1430    for( j = 1; j < nmyitems; ++j )
1431    {
1432       int intweight;
1433 
1434       /* compute important part of weight, which will be represented in the table */
1435       intweight = (int)(myweights[j] - minweight);
1436       assert(0 <= intweight && intweight < intcap);
1437 
1438       /* copy all nonzeros from row above */
1439       for( d = currminweight; d < intweight && d < intcap; ++d )
1440          optvalues[IDX(j,d)] = optvalues[IDX(j-1,d)];
1441 
1442       /* update corresponding row */
1443       for( d = intweight; d < intcap; ++d )
1444       {
1445          /* if index d < current minweight then optvalues[IDX(j-1,d)] is not initialized, i.e. should be 0 */
1446          if( d < currminweight )
1447             optvalues[IDX(j,d)] = myprofits[j];
1448          else
1449          {
1450             SCIP_Real sumprofit;
1451 
1452             if( d - myweights[j] < currminweight )
1453                sumprofit = myprofits[j];
1454             else
1455                sumprofit = optvalues[IDX(j-1,(int)(d-myweights[j]))] + myprofits[j];
1456 
1457             optvalues[IDX(j,d)] = MAX(sumprofit, optvalues[IDX(j-1,d)]);
1458          }
1459       }
1460 
1461       /* update currminweight */
1462       if( intweight < currminweight )
1463          currminweight = intweight;
1464 
1465       allcurrminweight[j] = currminweight;
1466    }
1467 
1468    /* update optimal solution by following the table */
1469    if( solitems != NULL )
1470    {
1471       assert(nsolitems != NULL && nonsolitems != NULL && nnonsolitems != NULL);
1472       d = intcap - 1;
1473 
1474       SCIPdebugMsg(scip, "Fill the solution vector after solving exactly.\n");
1475 
1476       /* insert all items in (non-) solution vector */
1477       for( j = nmyitems - 1; j > 0; --j )
1478       {
1479          /* if the following condition holds this means all remaining items does not fit anymore */
1480          if( d < allcurrminweight[j] )
1481          {
1482             /* we cannot have exceeded our capacity */
1483             assert((SCIP_Longint) d >= -minweight);
1484             break;
1485          }
1486 
1487          /* collect solution items; the first condition means that no further item can fit anymore, but this does */
1488          if( d < allcurrminweight[j-1] || optvalues[IDX(j,d)] > optvalues[IDX(j-1,d)] )
1489          {
1490             solitems[(*nsolitems)++] = myitems[j];
1491 
1492             /* check that we do not have an underflow */
1493             assert(myweights[j] <= (INT_MAX + (SCIP_Longint) d));
1494             d = (int)(d - myweights[j]);
1495          }
1496          /* collect non-solution items */
1497          else
1498             nonsolitems[(*nnonsolitems)++] = myitems[j];
1499       }
1500 
1501       /* insert remaining items */
1502       if( d >= allcurrminweight[j] )
1503       {
1504          assert(j == 0);
1505          solitems[(*nsolitems)++] = myitems[j];
1506       }
1507       else
1508       {
1509          assert(j >= 0);
1510          assert(d < allcurrminweight[j]);
1511 
1512          for( ; j >= 0; --j )
1513             nonsolitems[(*nnonsolitems)++] = myitems[j];
1514       }
1515 
1516       assert(*nsolitems + *nnonsolitems == nitems);
1517    }
1518 
1519    /* update solution value */
1520    if( solval != NULL )
1521       *solval += optvalues[IDX(nmyitems-1,intcap-1)];
1522    SCIPfreeBufferArray(scip, &allcurrminweight);
1523 
1524    /* free all temporary memory */
1525    SCIPfreeBufferArray(scip, &optvalues);
1526 
1527  TERMINATE:
1528    SCIPfreeBufferArray(scip, &myitems);
1529    SCIPfreeBufferArray(scip, &myprofits);
1530    SCIPfreeBufferArray(scip, &myweights);
1531 
1532    return SCIP_OKAY;
1533 }
1534 
1535 /** solves knapsack problem in maximization form approximately by solving the LP-relaxation of the problem using Dantzig's
1536  *  method and rounding down the solution; if needed, one can provide arrays to store all selected items and all not
1537  *  selected items
1538  */
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)1539 SCIP_RETCODE SCIPsolveKnapsackApproximately(
1540    SCIP*                 scip,               /**< SCIP data structure */
1541    int                   nitems,             /**< number of available items */
1542    SCIP_Longint*         weights,            /**< item weights */
1543    SCIP_Real*            profits,            /**< item profits */
1544    SCIP_Longint          capacity,           /**< capacity of knapsack */
1545    int*                  items,              /**< item numbers */
1546    int*                  solitems,           /**< array to store items in solution, or NULL */
1547    int*                  nonsolitems,        /**< array to store items not in solution, or NULL */
1548    int*                  nsolitems,          /**< pointer to store number of items in solution, or NULL */
1549    int*                  nnonsolitems,       /**< pointer to store number of items not in solution, or NULL */
1550    SCIP_Real*            solval              /**< pointer to store optimal solution value, or NULL */
1551    )
1552 {
1553    SCIP_Real* tempsort;
1554    SCIP_Longint solitemsweight;
1555    SCIP_Real* realweights;
1556    int j;
1557    int criticalindex;
1558 
1559    assert(weights != NULL);
1560    assert(profits != NULL);
1561    assert(capacity >= 0);
1562    assert(items != NULL);
1563    assert(nitems >= 0);
1564 
1565    if( solitems != NULL )
1566    {
1567       *nsolitems = 0;
1568       *nnonsolitems = 0;
1569    }
1570    if( solval != NULL )
1571       *solval = 0.0;
1572 
1573    /* initialize data for median search */
1574    SCIP_CALL( SCIPallocBufferArray(scip, &tempsort, nitems) );
1575    SCIP_CALL( SCIPallocBufferArray(scip, &realweights, nitems) );
1576    for( j = nitems - 1; j >= 0; --j )
1577    {
1578       tempsort[j] = profits[j]/((SCIP_Real) weights[j]);
1579       realweights[j] = (SCIP_Real)weights[j];
1580    }
1581 
1582    /* partially sort indices such that all elements that are larger than the break item appear first */
1583    SCIPselectWeightedDownRealLongRealInt(tempsort, weights, profits, items, realweights, (SCIP_Real)capacity, nitems, &criticalindex);
1584 
1585    /* selects items as long as they fit into the knapsack */
1586    solitemsweight = 0;
1587    for( j = 0; j < nitems && solitemsweight + weights[j] <= capacity; ++j )
1588    {
1589       if( solitems != NULL )
1590          solitems[(*nsolitems)++] = items[j];
1591 
1592       if( solval != NULL )
1593          (*solval) += profits[j];
1594       solitemsweight += weights[j];
1595    }
1596    if ( solitems != NULL )
1597    {
1598       for( ; j < nitems; j++ )
1599          nonsolitems[(*nnonsolitems)++] = items[j];
1600    }
1601 
1602    SCIPfreeBufferArray(scip, &realweights);
1603    SCIPfreeBufferArray(scip, &tempsort);
1604 
1605    return SCIP_OKAY;
1606 }
1607 
1608 #ifdef SCIP_DEBUG
1609 /** prints all nontrivial GUB constraints and their LP solution values */
1610 static
GUBsetPrint(SCIP * scip,SCIP_GUBSET * gubset,SCIP_VAR ** vars,SCIP_Real * solvals)1611 void GUBsetPrint(
1612    SCIP*                 scip,               /**< SCIP data structure */
1613    SCIP_GUBSET*          gubset,             /**< GUB set data structure */
1614    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
1615    SCIP_Real*            solvals             /**< solution values of variables in knapsack constraint; or NULL */
1616    )
1617 {
1618    int nnontrivialgubconss;
1619    int c;
1620 
1621    nnontrivialgubconss = 0;
1622 
1623    SCIPdebugMsg(scip, "   Nontrivial GUBs of current GUB set:\n");
1624 
1625    /* print out all nontrivial GUB constraints, i.e., with more than one variable */
1626    for( c = 0; c < gubset->ngubconss; c++ )
1627    {
1628       SCIP_Real gubsolval;
1629 
1630       assert(gubset->gubconss[c]->ngubvars >= 0);
1631 
1632       /* nontrivial GUB */
1633       if( gubset->gubconss[c]->ngubvars > 1 )
1634       {
1635          int v;
1636 
1637          gubsolval = 0.0;
1638          SCIPdebugMsg(scip, "   GUB<%d>:\n", c);
1639 
1640          /* print GUB var */
1641          for( v = 0; v < gubset->gubconss[c]->ngubvars; v++ )
1642          {
1643             int currentvar;
1644 
1645             currentvar = gubset->gubconss[c]->gubvars[v];
1646             if( solvals != NULL )
1647             {
1648                gubsolval += solvals[currentvar];
1649                SCIPdebugMsg(scip, "      +<%s>(%4.2f)\n", SCIPvarGetName(vars[currentvar]), solvals[currentvar]);
1650             }
1651             else
1652             {
1653                SCIPdebugMsg(scip, "      +<%s>\n", SCIPvarGetName(vars[currentvar]));
1654             }
1655          }
1656 
1657 	 /* check whether LP solution satisfies the GUB constraint */
1658          if( solvals != NULL )
1659          {
1660             SCIPdebugMsg(scip, "      =%4.2f <= 1 %s\n", gubsolval,
1661                SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1662          }
1663          else
1664          {
1665             SCIPdebugMsg(scip, "      <= 1 %s\n", SCIPisFeasGT(scip, gubsolval, 1.0) ? "--> violated" : "");
1666          }
1667          nnontrivialgubconss++;
1668       }
1669    }
1670 
1671    SCIPdebugMsg(scip, "   --> %d/%d nontrivial GUBs\n", nnontrivialgubconss, gubset->ngubconss);
1672 }
1673 #endif
1674 
1675 /** creates an empty GUB constraint */
1676 static
GUBconsCreate(SCIP * scip,SCIP_GUBCONS ** gubcons)1677 SCIP_RETCODE GUBconsCreate(
1678    SCIP*                 scip,               /**< SCIP data structure */
1679    SCIP_GUBCONS**        gubcons             /**< pointer to store GUB constraint data */
1680    )
1681 {
1682    assert(scip != NULL);
1683    assert(gubcons != NULL);
1684 
1685    /* allocate memory for GUB constraint data structures */
1686    SCIP_CALL( SCIPallocBuffer(scip, gubcons) );
1687    (*gubcons)->gubvarssize = GUBCONSGROWVALUE;
1688    SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvars, (*gubcons)->gubvarssize) );
1689    SCIP_CALL( SCIPallocBufferArray(scip, &(*gubcons)->gubvarsstatus, (*gubcons)->gubvarssize) );
1690 
1691    (*gubcons)->ngubvars = 0;
1692 
1693    return SCIP_OKAY;
1694 }
1695 
1696 /** frees GUB constraint */
1697 static
GUBconsFree(SCIP * scip,SCIP_GUBCONS ** gubcons)1698 void GUBconsFree(
1699    SCIP*                 scip,               /**< SCIP data structure */
1700    SCIP_GUBCONS**        gubcons             /**< pointer to GUB constraint data structure */
1701    )
1702 {
1703    assert(scip != NULL);
1704    assert(gubcons != NULL);
1705    assert((*gubcons)->gubvars != NULL);
1706    assert((*gubcons)->gubvarsstatus != NULL);
1707 
1708    /* free allocated memory */
1709    SCIPfreeBufferArray(scip, &(*gubcons)->gubvarsstatus);
1710    SCIPfreeBufferArray(scip, &(*gubcons)->gubvars);
1711    SCIPfreeBuffer(scip, gubcons);
1712 }
1713 
1714 /** adds variable to given GUB constraint */
1715 static
GUBconsAddVar(SCIP * scip,SCIP_GUBCONS * gubcons,int var)1716 SCIP_RETCODE GUBconsAddVar(
1717    SCIP*                 scip,               /**< SCIP data structure */
1718    SCIP_GUBCONS*         gubcons,            /**< GUB constraint data */
1719    int                   var                 /**< index of given variable in knapsack constraint */
1720    )
1721 {
1722    assert(scip != NULL);
1723    assert(gubcons != NULL);
1724    assert(gubcons->ngubvars >= 0 && gubcons->ngubvars < gubcons->gubvarssize);
1725    assert(gubcons->gubvars != NULL);
1726    assert(gubcons->gubvarsstatus != NULL);
1727    assert(var >= 0);
1728 
1729    /* add variable to GUB constraint */
1730    gubcons->gubvars[gubcons->ngubvars] = var;
1731    gubcons->gubvarsstatus[gubcons->ngubvars] = GUBVARSTATUS_UNINITIAL;
1732    gubcons->ngubvars++;
1733 
1734    /* increase space allocated to GUB constraint if the number of variables reaches the size */
1735    if( gubcons->ngubvars == gubcons->gubvarssize )
1736    {
1737       int newlen;
1738 
1739       newlen = gubcons->gubvarssize + GUBCONSGROWVALUE;
1740       SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1741       SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1742 
1743       gubcons->gubvarssize = newlen;
1744    }
1745 
1746    return SCIP_OKAY;
1747 }
1748 
1749 /** deletes variable from its current GUB constraint */
1750 static
GUBconsDelVar(SCIP * scip,SCIP_GUBCONS * gubcons,int var,int gubvarsidx)1751 SCIP_RETCODE GUBconsDelVar(
1752    SCIP*                 scip,               /**< SCIP data structure */
1753    SCIP_GUBCONS*         gubcons,            /**< GUB constraint data */
1754    int                   var,                /**< index of given variable in knapsack constraint */
1755    int                   gubvarsidx          /**< index of the variable in its current GUB constraint */
1756    )
1757 {
1758    assert(scip != NULL);
1759    assert(gubcons != NULL);
1760    assert(var >= 0);
1761    assert(gubvarsidx >= 0 && gubvarsidx < gubcons->ngubvars);
1762    assert(gubcons->ngubvars >= gubvarsidx+1);
1763    assert(gubcons->gubvars[gubvarsidx] == var);
1764 
1765    /* delete variable from GUB by swapping it replacing in by the last variable in the GUB constraint */
1766    gubcons->gubvars[gubvarsidx] = gubcons->gubvars[gubcons->ngubvars-1];
1767    gubcons->gubvarsstatus[gubvarsidx] = gubcons->gubvarsstatus[gubcons->ngubvars-1];
1768    gubcons->ngubvars--;
1769 
1770    /* decrease space allocated for the GUB constraint, if the last GUBCONSGROWVALUE+1 array entries are now empty */
1771    if( gubcons->ngubvars < gubcons->gubvarssize - GUBCONSGROWVALUE && gubcons->ngubvars > 0 )
1772    {
1773       int newlen;
1774 
1775       newlen = gubcons->gubvarssize - GUBCONSGROWVALUE;
1776 
1777       SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvars, newlen) );
1778       SCIP_CALL( SCIPreallocBufferArray(scip, &gubcons->gubvarsstatus, newlen) );
1779 
1780       gubcons->gubvarssize = newlen;
1781    }
1782 
1783    return SCIP_OKAY;
1784 }
1785 
1786 /** moves variable from current GUB constraint to a different existing (nonempty) GUB constraint */
1787 static
GUBsetMoveVar(SCIP * scip,SCIP_GUBSET * gubset,SCIP_VAR ** vars,int var,int oldgubcons,int newgubcons)1788 SCIP_RETCODE GUBsetMoveVar(
1789    SCIP*                 scip,               /**< SCIP data structure */
1790    SCIP_GUBSET*          gubset,             /**< GUB set data structure */
1791    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
1792    int                   var,                /**< index of given variable in knapsack constraint */
1793    int                   oldgubcons,         /**< index of old GUB constraint of given variable */
1794    int                   newgubcons          /**< index of new GUB constraint of given variable */
1795    )
1796 {
1797    int oldgubvaridx;
1798    int replacevar;
1799    int j;
1800 
1801    assert(scip != NULL);
1802    assert(gubset != NULL);
1803    assert(var >= 0);
1804    assert(oldgubcons >= 0 && oldgubcons < gubset->ngubconss);
1805    assert(newgubcons >= 0 && newgubcons < gubset->ngubconss);
1806    assert(oldgubcons != newgubcons);
1807    assert(gubset->gubconssidx[var] == oldgubcons);
1808    assert(gubset->gubconss[oldgubcons]->ngubvars > 0);
1809    assert(gubset->gubconss[newgubcons]->ngubvars >= 0);
1810 
1811    SCIPdebugMsg(scip, "   moving variable<%s> from GUB<%d> to GUB<%d>\n", SCIPvarGetName(vars[var]), oldgubcons, newgubcons);
1812 
1813    oldgubvaridx = gubset->gubvarsidx[var];
1814 
1815    /* delete variable from old GUB constraint by replacing it by the last variable of the GUB constraint */
1816    SCIP_CALL( GUBconsDelVar(scip, gubset->gubconss[oldgubcons], var, oldgubvaridx) );
1817 
1818    /* in GUB set, update stored index of variable in old GUB constraint for the variable used for replacement;
1819     * replacement variable is given by old position of the deleted variable
1820     */
1821    replacevar = gubset->gubconss[oldgubcons]->gubvars[oldgubvaridx];
1822    assert(gubset->gubvarsidx[replacevar] == gubset->gubconss[oldgubcons]->ngubvars);
1823    gubset->gubvarsidx[replacevar] = oldgubvaridx;
1824 
1825    /* add variable to the end of new GUB constraint */
1826    SCIP_CALL( GUBconsAddVar(scip, gubset->gubconss[newgubcons], var) );
1827    assert(gubset->gubconss[newgubcons]->gubvars[gubset->gubconss[newgubcons]->ngubvars-1] == var);
1828 
1829    /* in GUB set, update stored index of GUB of moved variable and stored index of variable in this GUB constraint */
1830    gubset->gubconssidx[var] = newgubcons;
1831    gubset->gubvarsidx[var] = gubset->gubconss[newgubcons]->ngubvars-1;
1832 
1833    /* delete old GUB constraint if it became empty */
1834    if( gubset->gubconss[oldgubcons]->ngubvars == 0 )
1835    {
1836       SCIPdebugMsg(scip, "deleting empty GUB cons<%d> from current GUB set\n", oldgubcons);
1837 #ifdef SCIP_DEBUG
1838       GUBsetPrint(scip, gubset, vars, NULL);
1839 #endif
1840 
1841       /* free old GUB constraint */
1842       GUBconsFree(scip, &gubset->gubconss[oldgubcons]);
1843 
1844       /* if empty GUB was not the last one in GUB set data structure, replace it by last GUB constraint */
1845       if( oldgubcons != gubset->ngubconss-1 )
1846       {
1847          gubset->gubconss[oldgubcons] = gubset->gubconss[gubset->ngubconss-1];
1848          gubset->gubconsstatus[oldgubcons] = gubset->gubconsstatus[gubset->ngubconss-1];
1849 
1850          /* in GUB set, update stored index of GUB constraint for all variable of the GUB constraint used for replacement;
1851           * replacement GUB is given by old position of the deleted GUB
1852           */
1853          for( j = 0; j < gubset->gubconss[oldgubcons]->ngubvars; j++ )
1854          {
1855             assert(gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] == gubset->ngubconss-1);
1856             gubset->gubconssidx[gubset->gubconss[oldgubcons]->gubvars[j]] = oldgubcons;
1857          }
1858       }
1859 
1860       /* update number of GUB constraints */
1861       gubset->ngubconss--;
1862 
1863       /* variable should be at given new position, unless new GUB constraint replaced empty old GUB constraint
1864        * (because it was at the end of the GUB constraint array)
1865        */
1866       assert(gubset->gubconssidx[var] == newgubcons
1867          || (newgubcons == gubset->ngubconss && gubset->gubconssidx[var] == oldgubcons));
1868    }
1869 #ifndef NDEBUG
1870    else
1871       assert(gubset->gubconssidx[var] == newgubcons);
1872 #endif
1873 
1874    return SCIP_OKAY;
1875 }
1876 
1877 /** swaps two variables in the same GUB constraint */
1878 static
GUBsetSwapVars(SCIP * scip,SCIP_GUBSET * gubset,int var1,int var2)1879 void GUBsetSwapVars(
1880    SCIP*                 scip,               /**< SCIP data structure */
1881    SCIP_GUBSET*          gubset,             /**< GUB set data structure */
1882    int                   var1,               /**< first variable to be swapped */
1883    int                   var2                /**< second variable to be swapped */
1884    )
1885 {
1886    int gubcons;
1887    int var1idx;
1888    GUBVARSTATUS var1status;
1889    int var2idx;
1890    GUBVARSTATUS var2status;
1891 
1892    assert(scip != NULL);
1893    assert(gubset != NULL);
1894 
1895    gubcons = gubset->gubconssidx[var1];
1896    assert(gubcons == gubset->gubconssidx[var2]);
1897 
1898    /* nothing to be done if both variables are the same */
1899    if( var1 == var2 )
1900       return;
1901 
1902    /* swap index and status of variables in GUB constraint */
1903    var1idx = gubset->gubvarsidx[var1];
1904    var1status = gubset->gubconss[gubcons]->gubvarsstatus[var1idx];
1905    var2idx = gubset->gubvarsidx[var2];
1906    var2status = gubset->gubconss[gubcons]->gubvarsstatus[var2idx];
1907 
1908    gubset->gubvarsidx[var1] = var2idx;
1909    gubset->gubconss[gubcons]->gubvars[var1idx] = var2;
1910    gubset->gubconss[gubcons]->gubvarsstatus[var1idx] = var2status;
1911 
1912    gubset->gubvarsidx[var2] = var1idx;
1913    gubset->gubconss[gubcons]->gubvars[var2idx] = var1;
1914    gubset->gubconss[gubcons]->gubvarsstatus[var2idx] = var1status;
1915 }
1916 
1917 /** initializes partition of knapsack variables into nonoverlapping trivial GUB constraints (GUB with one variable) */
1918 static
GUBsetCreate(SCIP * scip,SCIP_GUBSET ** gubset,int nvars,SCIP_Longint * weights,SCIP_Longint capacity)1919 SCIP_RETCODE GUBsetCreate(
1920    SCIP*                 scip,               /**< SCIP data structure */
1921    SCIP_GUBSET**         gubset,             /**< pointer to store GUB set data structure */
1922    int                   nvars,              /**< number of variables in the knapsack constraint */
1923    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
1924    SCIP_Longint          capacity            /**< capacity of knapsack */
1925    )
1926 {
1927    int i;
1928 
1929    assert(scip != NULL);
1930    assert(gubset != NULL);
1931    assert(nvars > 0);
1932    assert(weights != NULL);
1933    assert(capacity >= 0);
1934 
1935    /* allocate memory for GUB set data structures */
1936    SCIP_CALL( SCIPallocBuffer(scip, gubset) );
1937    SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconss, nvars) );
1938    SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconsstatus, nvars) );
1939    SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubconssidx, nvars) );
1940    SCIP_CALL( SCIPallocBufferArray(scip, &(*gubset)->gubvarsidx, nvars) );
1941    (*gubset)->ngubconss = nvars;
1942    (*gubset)->nvars = nvars;
1943 
1944    /* initialize the set of GUB constraints */
1945    for( i = 0; i < nvars; i++ )
1946    {
1947       /* assign each variable to a new (trivial) GUB constraint */
1948       SCIP_CALL( GUBconsCreate(scip, &(*gubset)->gubconss[i]) );
1949       SCIP_CALL( GUBconsAddVar(scip, (*gubset)->gubconss[i], i) );
1950 
1951       /* set status of GUB constraint to initial */
1952       (*gubset)->gubconsstatus[i] = GUBCONSSTATUS_UNINITIAL;
1953 
1954       (*gubset)->gubconssidx[i] = i;
1955       (*gubset)->gubvarsidx[i] = 0;
1956       assert((*gubset)->gubconss[i]->ngubvars == 1);
1957 
1958       /* already updated status of variable in GUB constraint if it exceeds the capacity of the knapsack */
1959       if( weights[i] > capacity )
1960          (*gubset)->gubconss[(*gubset)->gubconssidx[i]]->gubvarsstatus[(*gubset)->gubvarsidx[i]] = GUBVARSTATUS_CAPACITYEXCEEDED;
1961    }
1962 
1963    return SCIP_OKAY;
1964 }
1965 
1966 /** frees GUB set data structure */
1967 static
GUBsetFree(SCIP * scip,SCIP_GUBSET ** gubset)1968 void GUBsetFree(
1969    SCIP*                 scip,               /**< SCIP data structure */
1970    SCIP_GUBSET**         gubset              /**< pointer to GUB set data structure */
1971    )
1972 {
1973    int i;
1974 
1975    assert(scip != NULL);
1976    assert(gubset != NULL);
1977    assert((*gubset)->gubconss != NULL);
1978    assert((*gubset)->gubconsstatus != NULL);
1979    assert((*gubset)->gubconssidx != NULL);
1980    assert((*gubset)->gubvarsidx != NULL);
1981 
1982    /* free all GUB constraints */
1983    for( i = (*gubset)->ngubconss-1; i >= 0; --i )
1984    {
1985       assert((*gubset)->gubconss[i] != NULL);
1986       GUBconsFree(scip, &(*gubset)->gubconss[i]);
1987    }
1988 
1989    /* free allocated memory */
1990    SCIPfreeBufferArray( scip, &(*gubset)->gubvarsidx );
1991    SCIPfreeBufferArray( scip, &(*gubset)->gubconssidx );
1992    SCIPfreeBufferArray( scip, &(*gubset)->gubconsstatus );
1993    SCIPfreeBufferArray( scip, &(*gubset)->gubconss );
1994    SCIPfreeBuffer(scip, gubset);
1995 }
1996 
1997 #ifndef NDEBUG
1998 /** checks whether GUB set data structure is consistent */
1999 static
GUBsetCheck(SCIP * scip,SCIP_GUBSET * gubset,SCIP_VAR ** vars)2000 SCIP_RETCODE GUBsetCheck(
2001    SCIP*                 scip,               /**< SCIP data structure */
2002    SCIP_GUBSET*          gubset,             /**< GUB set data structure */
2003    SCIP_VAR**            vars                /**< variables in the knapsack constraint */
2004    )
2005 {
2006    int i;
2007    int gubconsidx;
2008    int gubvaridx;
2009    SCIP_VAR* var1;
2010    SCIP_VAR* var2;
2011    SCIP_Bool var1negated;
2012    SCIP_Bool var2negated;
2013 
2014    assert(scip != NULL);
2015    assert(gubset != NULL);
2016 
2017    SCIPdebugMsg(scip, "   GUB set consistency check:\n");
2018 
2019    /* checks for all knapsack vars consistency of stored index of associated gubcons and corresponding index in gubvars */
2020    for( i = 0; i < gubset->nvars; i++ )
2021    {
2022       gubconsidx = gubset->gubconssidx[i];
2023       gubvaridx = gubset->gubvarsidx[i];
2024 
2025       if( gubset->gubconss[gubconsidx]->gubvars[gubvaridx] != i )
2026       {
2027 	 SCIPdebugMsg(scip, "   var<%d> should be in GUB<%d> at position<%d>, but stored is var<%d> instead\n", i,
2028             gubconsidx, gubvaridx, gubset->gubconss[gubconsidx]->gubvars[gubvaridx] );
2029       }
2030       assert(gubset->gubconss[gubconsidx]->gubvars[gubvaridx] == i);
2031    }
2032 
2033    /* checks for each GUB whether all pairs of its variables have a common clique */
2034    for( i = 0; i < gubset->ngubconss; i++ )
2035    {
2036       int j;
2037 
2038       for( j = 0; j < gubset->gubconss[i]->ngubvars; j++ )
2039       {
2040          int k;
2041 
2042          /* get corresponding active problem variable */
2043          var1 = vars[gubset->gubconss[i]->gubvars[j]];
2044          var1negated = FALSE;
2045          SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &var1negated) );
2046 
2047          for( k = j+1; k < gubset->gubconss[i]->ngubvars; k++ )
2048          {
2049             /* get corresponding active problem variable */
2050             var2 = vars[gubset->gubconss[i]->gubvars[k]];
2051             var2negated = FALSE;
2052             SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &var2negated) );
2053 
2054             if( !SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE) )
2055             {
2056                SCIPdebugMsg(scip, "   GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2057                   SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[j]]), k,
2058                   SCIPvarGetName(vars[gubset->gubconss[i]->gubvars[k]]));
2059                SCIPdebugMsg(scip, "   GUB<%d>: var<%d,%s> and var<%d,%s> do not share a clique\n", i, j,
2060                   SCIPvarGetName(var1), k,
2061                   SCIPvarGetName(var2));
2062             }
2063 
2064             /* @todo: in case we used also negated cliques for the GUB partition, this assert has to be changed */
2065             assert(SCIPvarsHaveCommonClique(var1, !var1negated, var2, !var2negated, TRUE));
2066          }
2067       }
2068    }
2069    SCIPdebugMsg(scip, "   --> successful\n");
2070 
2071    return SCIP_OKAY;
2072 }
2073 #endif
2074 
2075 /** calculates a partition of the given set of binary variables into cliques;
2076  *  afterwards the output array contains one value for each variable, such that two variables got the same value iff they
2077  *  were assigned to the same clique;
2078  *  the first variable is always assigned to clique 0, and a variable can only be assigned to clique i if at least one of
2079  *  the preceding variables was assigned to clique i-1;
2080  *  note: in contrast to SCIPcalcCliquePartition(), variables with LP value 1 are put into trivial cliques (with one
2081  *  variable) and for the remaining variables, a partition with a small number of cliques is constructed
2082  */
2083 
2084 static
GUBsetCalcCliquePartition(SCIP * const scip,SCIP_VAR ** const vars,int const nvars,int * const cliquepartition,int * const ncliques,SCIP_Real * solvals)2085 SCIP_RETCODE GUBsetCalcCliquePartition(
2086    SCIP*const            scip,               /**< SCIP data structure */
2087    SCIP_VAR**const       vars,               /**< binary variables in the clique from which at most one can be set to 1 */
2088    int const             nvars,              /**< number of variables in the clique */
2089    int*const             cliquepartition,    /**< array of length nvars to store the clique partition */
2090    int*const             ncliques,           /**< pointer to store number of cliques actually contained in the partition */
2091    SCIP_Real*            solvals             /**< solution values of all given binary variables */
2092    )
2093 {
2094    SCIP_VAR** tmpvars;
2095    SCIP_VAR** cliquevars;
2096    SCIP_Bool* cliquevalues;
2097    SCIP_Bool* tmpvalues;
2098    int* varseq;
2099    int* sortkeys;
2100    int ncliquevars;
2101    int maxncliquevarscomp;
2102    int nignorevars;
2103    int nvarsused;
2104    int i;
2105 
2106    assert(scip != NULL);
2107    assert(nvars == 0 || vars != NULL);
2108    assert(nvars == 0 || cliquepartition != NULL);
2109    assert(ncliques != NULL);
2110 
2111    if( nvars == 0 )
2112    {
2113       *ncliques = 0;
2114       return SCIP_OKAY;
2115    }
2116 
2117    /* allocate temporary memory for storing the variables of the current clique */
2118    SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
2119    SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, nvars) );
2120    SCIP_CALL( SCIPallocBufferArray(scip, &tmpvalues, nvars) );
2121    SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
2122    SCIP_CALL( SCIPallocBufferArray(scip, &varseq, nvars) );
2123    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvars) );
2124 
2125    /* initialize the cliquepartition array with -1 */
2126    /* initialize the tmpvalues array */
2127    for( i = nvars - 1; i >= 0; --i )
2128    {
2129       tmpvalues[i] = TRUE;
2130       cliquepartition[i] = -1;
2131    }
2132 
2133    /* get corresponding active problem variables */
2134    SCIP_CALL( SCIPvarsGetProbvarBinary(&tmpvars, &tmpvalues, nvars) );
2135 
2136    /* ignore variables with LP value 1 (will be assigned to trivial GUBs at the end) and sort remaining variables
2137     * by nondecreasing number of cliques the variables are in
2138     */
2139    nignorevars = 0;
2140    nvarsused = 0;
2141    for( i = 0; i < nvars; i++ )
2142    {
2143       if( SCIPisFeasEQ(scip, solvals[i], 1.0) )
2144       {
2145          /* variables with LP value 1 are put to the end of varseq array and will not be sorted */
2146          varseq[nvars-1-nignorevars] = i;
2147          nignorevars++;
2148       }
2149       else
2150       {
2151          /* remaining variables are put to the front of varseq array and will be sorted by their number of cliques */
2152          varseq[nvarsused] = i;
2153          sortkeys[nvarsused] = SCIPvarGetNCliques(tmpvars[i], tmpvalues[i]);
2154          nvarsused++;
2155       }
2156    }
2157    assert(nvarsused + nignorevars == nvars);
2158 
2159    /* sort variables with LP value less than 1 by nondecreasing order of the number of cliques they are in */
2160    SCIPsortIntInt(sortkeys, varseq, nvarsused);
2161 
2162    maxncliquevarscomp = MIN(nvars*nvars, MAXNCLIQUEVARSCOMP);
2163 
2164    /* calculate the clique partition */
2165    *ncliques = 0;
2166    for( i = 0; i < nvars; ++i )
2167    {
2168       if( cliquepartition[varseq[i]] == -1 )
2169       {
2170          int j;
2171 
2172          /* variable starts a new clique */
2173          cliquepartition[varseq[i]] = *ncliques;
2174          cliquevars[0] = tmpvars[varseq[i]];
2175          cliquevalues[0] = tmpvalues[varseq[i]];
2176          ncliquevars = 1;
2177 
2178          /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique and
2179           * if the variable has LP value 1 we do not want it to be in nontrivial cliques
2180           */
2181          if( SCIPvarIsActive(tmpvars[varseq[i]]) && i < nvarsused )
2182          {
2183             /* greedily fill up the clique */
2184             for( j = i + 1; j < nvarsused; ++j )
2185             {
2186                /* if variable is not active (multi-aggregated or fixed), it cannot be in any clique */
2187                if( cliquepartition[varseq[j]] == -1 && SCIPvarIsActive(tmpvars[varseq[j]]) )
2188                {
2189                   int k;
2190 
2191                   /* check if every variable in the actual clique is in clique with the new variable */
2192                   for( k = ncliquevars - 1; k >= 0; --k )
2193                   {
2194                      if( !SCIPvarsHaveCommonClique(tmpvars[varseq[j]], tmpvalues[varseq[j]], cliquevars[k],
2195                            cliquevalues[k], TRUE) )
2196                         break;
2197                   }
2198 
2199                   if( k == -1 )
2200                   {
2201                      /* put the variable into the same clique */
2202                      cliquepartition[varseq[j]] = cliquepartition[varseq[i]];
2203                      cliquevars[ncliquevars] = tmpvars[varseq[j]];
2204                      cliquevalues[ncliquevars] = tmpvalues[varseq[j]];
2205                      ++ncliquevars;
2206                   }
2207                }
2208             }
2209          }
2210 
2211          /* this clique is finished */
2212          ++(*ncliques);
2213       }
2214       assert(cliquepartition[varseq[i]] >= 0 && cliquepartition[varseq[i]] < i + 1);
2215 
2216       /* break if we reached the maximal number of comparisons */
2217       if( i * nvars > maxncliquevarscomp )
2218          break;
2219    }
2220    /* if we had too many variables fill up the cliquepartition and put each variable in a separate clique */
2221    for( ; i < nvars; ++i )
2222    {
2223       if( cliquepartition[varseq[i]] == -1 )
2224       {
2225          cliquepartition[varseq[i]] = *ncliques;
2226          ++(*ncliques);
2227       }
2228    }
2229 
2230    /* free temporary memory */
2231    SCIPfreeBufferArray(scip, &sortkeys);
2232    SCIPfreeBufferArray(scip, &varseq);
2233    SCIPfreeBufferArray(scip, &tmpvars);
2234    SCIPfreeBufferArray(scip, &tmpvalues);
2235    SCIPfreeBufferArray(scip, &cliquevalues);
2236    SCIPfreeBufferArray(scip, &cliquevars);
2237 
2238    return SCIP_OKAY;
2239 }
2240 
2241 /** constructs sophisticated partition of knapsack variables into non-overlapping GUBs; current partition uses trivial GUBs */
2242 static
GUBsetGetCliquePartition(SCIP * scip,SCIP_GUBSET * gubset,SCIP_VAR ** vars,SCIP_Real * solvals)2243 SCIP_RETCODE GUBsetGetCliquePartition(
2244    SCIP*                 scip,               /**< SCIP data structure */
2245    SCIP_GUBSET*          gubset,             /**< GUB set data structure */
2246    SCIP_VAR**            vars,               /**< variables in the knapsack constraint */
2247    SCIP_Real*            solvals             /**< solution values of all knapsack variables */
2248    )
2249 {
2250    int* cliquepartition;
2251    int* gubfirstvar;
2252    int ncliques;
2253    int currentgubconsidx;
2254    int newgubconsidx;
2255    int cliqueidx;
2256    int nvars;
2257    int i;
2258 
2259    assert(scip != NULL);
2260    assert(gubset != NULL);
2261    assert(vars != NULL);
2262 
2263    nvars = gubset->nvars;
2264    assert(nvars >= 0);
2265 
2266    /* allocate temporary memory for clique partition */
2267    SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nvars) );
2268 
2269    /* compute sophisticated clique partition */
2270    SCIP_CALL( GUBsetCalcCliquePartition(scip, vars, nvars, cliquepartition, &ncliques, solvals) );
2271 
2272    /* allocate temporary memory for GUB set data structure */
2273    SCIP_CALL( SCIPallocBufferArray(scip, &gubfirstvar, ncliques) );
2274 
2275    /* translate GUB partition into GUB set data structure */
2276    for( i = 0; i < ncliques; i++ )
2277    {
2278       /* initialize first variable for every GUB */
2279       gubfirstvar[i] = -1;
2280    }
2281    /* move every knapsack variable into GUB defined by clique partition */
2282    for( i = 0; i < nvars; i++ )
2283    {
2284       assert(cliquepartition[i] >= 0);
2285 
2286       cliqueidx = cliquepartition[i];
2287       currentgubconsidx = gubset->gubconssidx[i];
2288       assert(gubset->gubconss[currentgubconsidx]->ngubvars == 1 );
2289 
2290       /* variable is first element in GUB constraint defined by clique partition */
2291       if( gubfirstvar[cliqueidx] == -1 )
2292       {
2293          /* corresponding GUB constraint in GUB set data structure was already constructed (as initial trivial GUB);
2294           * note: no assert for gubconssidx, because it can changed due to deleting empty GUBs in GUBsetMoveVar()
2295           */
2296          assert(gubset->gubvarsidx[i] == 0);
2297          assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2298 
2299          /* remember the first variable found for the current GUB */
2300          gubfirstvar[cliqueidx] = i;
2301       }
2302       /* variable is additional element of GUB constraint defined by clique partition */
2303       else
2304       {
2305          assert(gubfirstvar[cliqueidx] >= 0 && gubfirstvar[cliqueidx] < i);
2306 
2307          /* move variable to GUB constraint defined by clique partition; index of this GUB constraint is given by the
2308           * first variable of this GUB constraint
2309           */
2310          newgubconsidx = gubset->gubconssidx[gubfirstvar[cliqueidx]];
2311          assert(newgubconsidx != currentgubconsidx); /* because initially every variable is in a different GUB */
2312          SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, i, currentgubconsidx, newgubconsidx) );
2313 
2314          assert(gubset->gubconss[gubset->gubconssidx[i]]->gubvars[gubset->gubvarsidx[i]] == i);
2315       }
2316    }
2317 
2318 #ifdef SCIP_DEBUG
2319    /* prints GUB set data structure */
2320    GUBsetPrint(scip, gubset, vars, solvals);
2321 #endif
2322 
2323 #ifndef NDEBUG
2324    /* checks consistency of GUB set data structure */
2325    SCIP_CALL( GUBsetCheck(scip, gubset, vars) );
2326 #endif
2327 
2328    /* free temporary memory */
2329    SCIPfreeBufferArray(scip, &gubfirstvar);
2330    SCIPfreeBufferArray(scip, &cliquepartition);
2331 
2332    return SCIP_OKAY;
2333 }
2334 
2335 /** 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$
2336  *  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
2337  *  \f$j \in N \setminus C\f$, if \f$j \in N_0 = \{j \in N : x^*_j = 0\}\f$, if one exists.
2338  */
2339 static
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)2340 SCIP_RETCODE getCover(
2341    SCIP*                 scip,               /**< SCIP data structure */
2342    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
2343    int                   nvars,              /**< number of variables in knapsack constraint */
2344    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
2345    SCIP_Longint          capacity,           /**< capacity of knapsack */
2346    SCIP_Real*            solvals,            /**< solution values of all problem variables */
2347    int*                  covervars,          /**< pointer to store cover variables */
2348    int*                  noncovervars,       /**< pointer to store noncover variables */
2349    int*                  ncovervars,         /**< pointer to store number of cover variables */
2350    int*                  nnoncovervars,      /**< pointer to store number of noncover variables */
2351    SCIP_Longint*         coverweight,        /**< pointer to store weight of cover */
2352    SCIP_Bool*            found,              /**< pointer to store whether a cover was found */
2353    SCIP_Bool             modtransused,       /**< should modified transformed separation problem be used to find cover */
2354    int*                  ntightened,         /**< pointer to store number of variables with tightened upper bound */
2355    SCIP_Bool*            fractional          /**< pointer to store whether the LP sol for knapsack vars is fractional */
2356    )
2357 {
2358    SCIP_Longint* transweights;
2359    SCIP_Real* transprofits;
2360    SCIP_Longint transcapacity;
2361    SCIP_Longint fixedonesweight;
2362    SCIP_Longint itemsweight;
2363    SCIP_Bool infeasible;
2364    int* fixedones;
2365    int* fixedzeros;
2366    int* items;
2367    int nfixedones;
2368    int nfixedzeros;
2369    int nitems;
2370    int j;
2371 
2372    assert(scip != NULL);
2373    assert(vars != NULL);
2374    assert(nvars > 0);
2375    assert(weights != NULL);
2376    assert(capacity >= 0);
2377    assert(solvals != NULL);
2378    assert(covervars != NULL);
2379    assert(noncovervars != NULL);
2380    assert(ncovervars != NULL);
2381    assert(nnoncovervars != NULL);
2382    assert(coverweight != NULL);
2383    assert(found != NULL);
2384    assert(ntightened != NULL);
2385    assert(fractional != NULL);
2386 
2387    SCIPdebugMsg(scip, "   get cover for knapsack constraint\n");
2388 
2389    /* allocates temporary memory */
2390    SCIP_CALL( SCIPallocBufferArray(scip, &transweights, nvars) );
2391    SCIP_CALL( SCIPallocBufferArray(scip, &transprofits, nvars) );
2392    SCIP_CALL( SCIPallocBufferArray(scip, &fixedones, nvars) );
2393    SCIP_CALL( SCIPallocBufferArray(scip, &fixedzeros, nvars) );
2394    SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
2395 
2396    *found = FALSE;
2397    *ncovervars = 0;
2398    *nnoncovervars = 0;
2399    *coverweight = 0;
2400    *fractional = TRUE;
2401 
2402    /* gets the following sets
2403     *  N_1 = {j in N : x*_j = 1} (fixedones),
2404     *  N_0 = {j in N : x*_j = 0} (fixedzeros) and
2405     *  N\(N_0 & N_1) (items),
2406     * where x*_j is the solution value of variable x_j
2407     */
2408    nfixedones = 0;
2409    nfixedzeros = 0;
2410    nitems = 0;
2411    fixedonesweight = 0;
2412    itemsweight = 0;
2413    *ntightened = 0;
2414    for( j = 0; j < nvars; j++ )
2415    {
2416       assert(SCIPvarIsBinary(vars[j]));
2417 
2418       /* tightens upper bound of x_j if weight of x_j is greater than capacity of knapsack */
2419       if( weights[j] > capacity )
2420       {
2421          SCIP_CALL( SCIPtightenVarUb(scip, vars[j], 0.0, FALSE, &infeasible, NULL) );
2422          assert(!infeasible);
2423          (*ntightened)++;
2424          continue;
2425       }
2426 
2427       /* variable x_j has solution value one */
2428       if( SCIPisFeasEQ(scip, solvals[j], 1.0) )
2429       {
2430          fixedones[nfixedones] = j;
2431          nfixedones++;
2432          fixedonesweight += weights[j];
2433       }
2434       /* variable x_j has solution value zero */
2435       else if( SCIPisFeasEQ(scip, solvals[j], 0.0) )
2436       {
2437          fixedzeros[nfixedzeros] = j;
2438          nfixedzeros++;
2439       }
2440       /* variable x_j has fractional solution value */
2441       else
2442       {
2443          assert( SCIPisFeasGT(scip, solvals[j], 0.0) && SCIPisFeasLT(scip, solvals[j], 1.0) );
2444          items[nitems] = j;
2445          nitems++;
2446          itemsweight += weights[j];
2447       }
2448    }
2449    assert(nfixedones + nfixedzeros + nitems == nvars - (*ntightened));
2450 
2451    /* sets whether the LP solution x* for the knapsack variables is fractional; if it is not fractional we stop
2452     * the separation routine
2453     */
2454    assert(nitems >= 0);
2455    if( nitems == 0 )
2456    {
2457       *fractional = FALSE;
2458       goto TERMINATE;
2459    }
2460    assert(*fractional);
2461 
2462    /* transforms the traditional separation problem (under consideration of the following fixing:
2463     * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2464     *
2465     *   min sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2466     *       sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2467     *                                    z_j in {0,1}, j in N\(N_0 & N_1)
2468     *
2469     * to a knapsack problem in maximization form by complementing the variables
2470     *
2471     * sum_{j in N\(N_0 & N_1)} (1 - x*_j) -
2472     *   max sum_{j in N\(N_0 & N_1)} (1 - x*_j) z_j
2473     *       sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2474     *                                    z_j in {0,1}, j in N\(N_0 & N_1)
2475     */
2476 
2477    /* gets weight and profit of variables in transformed knapsack problem */
2478    for( j = 0; j < nitems; j++ )
2479    {
2480       transweights[j] = weights[items[j]];
2481       transprofits[j] = 1.0 - solvals[items[j]];
2482    }
2483    /* gets capacity of transformed knapsack problem */
2484    transcapacity = fixedonesweight + itemsweight - capacity - 1;
2485 
2486    /* if capacity of transformed knapsack problem is less than zero, there is no cover
2487     * (when variables fixed to zero are not used)
2488     */
2489    if( transcapacity < 0 )
2490    {
2491       assert(!(*found));
2492       goto TERMINATE;
2493    }
2494 
2495    if( modtransused )
2496    {
2497       /* transforms the modified separation problem (under consideration of the following fixing:
2498        * z_j = 1 for all j in N_1, z_j = 0 for all j in N_0)
2499        *
2500        *   min sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2501        *       sum_{j in N\(N_0 & N_1)} a_j z_j >= (a_0 + 1) - sum_{j in N_1} a_j
2502        *                                    z_j in {0,1}, j in N\(N_0 & N_1)
2503        *
2504        * to a knapsack problem in maximization form by complementing the variables
2505        *
2506        * sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j -
2507        *   max sum_{j in N\(N_0 & N_1)} (1 - x*_j) a_j z_j
2508        *       sum_{j in N\(N_0 & N_1)} a_j z_j <= sum_{j in N\N_0} a_j - (a_0 + 1)
2509        *                                    z_j in {0,1}, j in N\(N_0 & N_1)
2510        */
2511 
2512       /* gets weight and profit of variables in modified transformed knapsack problem */
2513       for( j = 0; j < nitems; j++ )
2514       {
2515          transprofits[j] *= weights[items[j]];
2516          assert(SCIPisFeasPositive(scip, transprofits[j]));
2517       }
2518    }
2519 
2520    /* solves (modified) transformed knapsack problem approximately by solving the LP-relaxation of the (modified)
2521     * transformed knapsack problem using Dantzig's method and rounding down the solution.
2522     * let z* be the solution, then
2523     *   j in C,          if z*_j = 0 and
2524     *   i in N\C,        if z*_j = 1.
2525     */
2526    SCIP_CALL( SCIPsolveKnapsackApproximately(scip, nitems, transweights, transprofits, transcapacity, items,
2527          noncovervars, covervars, nnoncovervars, ncovervars, NULL) );
2528    /*assert(checkSolveKnapsack(scip, nitems, transweights, transprofits, items, weights, solvals, modtransused));*/
2529 
2530    /* constructs cover C (sum_{j in C} a_j > a_0) */
2531    for( j = 0; j < *ncovervars; j++ )
2532    {
2533       (*coverweight) += weights[covervars[j]];
2534    }
2535 
2536    /* adds all variables from N_1 to C */
2537    for( j = 0; j < nfixedones; j++ )
2538    {
2539       covervars[*ncovervars] = fixedones[j];
2540       (*ncovervars)++;
2541       (*coverweight) += weights[fixedones[j]];
2542    }
2543 
2544    /* adds all variables from N_0 to N\C */
2545    for( j = 0; j < nfixedzeros; j++ )
2546    {
2547       noncovervars[*nnoncovervars] = fixedzeros[j];
2548       (*nnoncovervars)++;
2549    }
2550    assert((*ncovervars) + (*nnoncovervars) == nvars - (*ntightened));
2551    assert((*coverweight) > capacity);
2552    *found = TRUE;
2553 
2554  TERMINATE:
2555    /* frees temporary memory */
2556    SCIPfreeBufferArray(scip, &items);
2557    SCIPfreeBufferArray(scip, &fixedzeros);
2558    SCIPfreeBufferArray(scip, &fixedones);
2559    SCIPfreeBufferArray(scip, &transprofits);
2560    SCIPfreeBufferArray(scip, &transweights);
2561 
2562    SCIPdebugMsg(scip, "   get cover for knapsack constraint -- end\n");
2563 
2564    return SCIP_OKAY;
2565 }
2566 
2567 #ifndef NDEBUG
2568 /** checks if minweightidx is set correctly
2569  */
2570 static
checkMinweightidx(SCIP_Longint * weights,SCIP_Longint capacity,int * covervars,int ncovervars,SCIP_Longint coverweight,int minweightidx,int j)2571 SCIP_Bool checkMinweightidx(
2572    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
2573    SCIP_Longint          capacity,           /**< capacity of knapsack */
2574    int*                  covervars,          /**< pointer to store cover variables */
2575    int                   ncovervars,         /**< pointer to store number of cover variables */
2576    SCIP_Longint          coverweight,        /**< pointer to store weight of cover */
2577    int                   minweightidx,       /**< index of variable in cover variables with minimum weight */
2578    int                   j                   /**< current index in cover variables */
2579    )
2580 {
2581    SCIP_Longint minweight;
2582    int i;
2583 
2584    assert(weights != NULL);
2585    assert(covervars != NULL);
2586    assert(ncovervars > 0);
2587 
2588    minweight = weights[covervars[minweightidx]];
2589 
2590    /* checks if all cover variables before index j have weight greater than minweight */
2591    for( i = 0; i < j; i++ )
2592    {
2593       assert(weights[covervars[i]] > minweight);
2594       if( weights[covervars[i]] <= minweight )
2595          return FALSE;
2596    }
2597 
2598    /* checks if all variables before index j cannot be removed, i.e. i cannot be the next minweightidx */
2599    for( i = 0; i < j; i++ )
2600    {
2601       assert(coverweight - weights[covervars[i]] <= capacity);
2602       if( coverweight - weights[covervars[i]] > capacity )
2603          return FALSE;
2604    }
2605    return TRUE;
2606 }
2607 #endif
2608 
2609 
2610 /** 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$,
2611  *  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$
2612  */
2613 static
getPartitionCovervars(SCIP * scip,SCIP_Real * solvals,int * covervars,int ncovervars,int * varsC1,int * varsC2,int * nvarsC1,int * nvarsC2)2614 void getPartitionCovervars(
2615    SCIP*                 scip,               /**< SCIP data structure */
2616    SCIP_Real*            solvals,            /**< solution values of all problem variables */
2617    int*                  covervars,          /**< cover variables */
2618    int                   ncovervars,         /**< number of cover variables */
2619    int*                  varsC1,             /**< pointer to store variables in C1 */
2620    int*                  varsC2,             /**< pointer to store variables in C2 */
2621    int*                  nvarsC1,            /**< pointer to store number of variables in C1 */
2622    int*                  nvarsC2             /**< pointer to store number of variables in C2 */
2623    )
2624 {
2625    int j;
2626 
2627    assert(scip != NULL);
2628    assert(ncovervars >= 0);
2629    assert(solvals != NULL);
2630    assert(covervars != NULL);
2631    assert(varsC1 != NULL);
2632    assert(varsC2 != NULL);
2633    assert(nvarsC1 != NULL);
2634    assert(nvarsC2 != NULL);
2635 
2636    *nvarsC1 = 0;
2637    *nvarsC2 = 0;
2638    for( j = 0; j < ncovervars; j++ )
2639    {
2640       assert(SCIPisFeasGT(scip, solvals[covervars[j]], 0.0));
2641 
2642       /* variable has solution value one */
2643       if( SCIPisGE(scip, solvals[covervars[j]], 1.0) )
2644       {
2645          varsC2[*nvarsC2] = covervars[j];
2646          (*nvarsC2)++;
2647       }
2648       /* variable has solution value less than one */
2649       else
2650       {
2651          assert(SCIPisLT(scip, solvals[covervars[j]], 1.0));
2652          varsC1[*nvarsC1] = covervars[j];
2653          (*nvarsC1)++;
2654       }
2655    }
2656    assert((*nvarsC1) + (*nvarsC2) == ncovervars);
2657 }
2658 
2659 /** changes given partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one and two (if possible) variables from
2660  *  C2 to C1 if |C1| = 1 and |C1| = 0, respectively.
2661  */
2662 static
changePartitionCovervars(SCIP * scip,SCIP_Longint * weights,int * varsC1,int * varsC2,int * nvarsC1,int * nvarsC2)2663 SCIP_RETCODE changePartitionCovervars(
2664    SCIP*                 scip,               /**< SCIP data structure */
2665    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
2666    int*                  varsC1,             /**< pointer to store variables in C1 */
2667    int*                  varsC2,             /**< pointer to store variables in C2 */
2668    int*                  nvarsC1,            /**< pointer to store number of variables in C1 */
2669    int*                  nvarsC2             /**< pointer to store number of variables in C2 */
2670    )
2671 {
2672    SCIP_Real* sortkeysC2;
2673    int j;
2674 
2675    assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2676    assert(*nvarsC2 > 0);
2677 
2678    /* allocates temporary memory */
2679    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2680 
2681    /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2682    for( j = 0; j < *nvarsC2; j++ )
2683       sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2684    SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2685 
2686    /* adds one or two variable from C2 with smallest weight to C1 and removes them from C2 */
2687    assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2688    while( *nvarsC1 < 2 && *nvarsC2 > 0 )
2689    {
2690       varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2691       (*nvarsC1)++;
2692       (*nvarsC2)--;
2693    }
2694 
2695    /* frees temporary memory */
2696    SCIPfreeBufferArray(scip, &sortkeysC2);
2697 
2698    return SCIP_OKAY;
2699 }
2700 
2701 /** changes given partition (C_1,C_2) of feasible set C, if |C1| = 1, by moving one variable from C2 to C1 */
2702 static
changePartitionFeasiblesetvars(SCIP * scip,SCIP_Longint * weights,int * varsC1,int * varsC2,int * nvarsC1,int * nvarsC2)2703 SCIP_RETCODE changePartitionFeasiblesetvars(
2704    SCIP*                 scip,               /**< SCIP data structure */
2705    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
2706    int*                  varsC1,             /**< pointer to store variables in C1 */
2707    int*                  varsC2,             /**< pointer to store variables in C2 */
2708    int*                  nvarsC1,            /**< pointer to store number of variables in C1 */
2709    int*                  nvarsC2             /**< pointer to store number of variables in C2 */
2710    )
2711 {
2712    SCIP_Real* sortkeysC2;
2713    int j;
2714 
2715    assert(*nvarsC1 >= 0 && *nvarsC1 <= 1);
2716    assert(*nvarsC2 > 0);
2717 
2718    /* allocates temporary memory */
2719    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, *nvarsC2) );
2720 
2721    /* sorts variables in C2 such that a_1 >= .... >= a_|C2| */
2722    for( j = 0; j < *nvarsC2; j++ )
2723       sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2724    SCIPsortDownRealInt(sortkeysC2, varsC2, *nvarsC2);
2725 
2726    /* adds variable from C2 with smallest weight to C1 and removes it from C2 */
2727    assert(*nvarsC2 == 1 || weights[varsC2[(*nvarsC2)-1]] <= weights[varsC2[(*nvarsC2)-2]]);
2728    varsC1[*nvarsC1] = varsC2[(*nvarsC2)-1];
2729    (*nvarsC1)++;
2730    (*nvarsC2)--;
2731 
2732    /* frees temporary memory */
2733    SCIPfreeBufferArray(scip, &sortkeysC2);
2734 
2735    return SCIP_OKAY;
2736 }
2737 
2738 
2739 /** 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$
2740  *  and \f$F \cap R = \emptyset\f$; chooses partition as follows \f$R = \{ j \in N \setminus C : x^*_j = 0 \}\f$ and
2741  *  \f$F = (N \setminus C) \setminus F\f$
2742  */
2743 static
getPartitionNoncovervars(SCIP * scip,SCIP_Real * solvals,int * noncovervars,int nnoncovervars,int * varsF,int * varsR,int * nvarsF,int * nvarsR)2744 void getPartitionNoncovervars(
2745    SCIP*                 scip,               /**< SCIP data structure */
2746    SCIP_Real*            solvals,            /**< solution values of all problem variables */
2747    int*                  noncovervars,       /**< noncover variables */
2748    int                   nnoncovervars,      /**< number of noncover variables */
2749    int*                  varsF,              /**< pointer to store variables in F */
2750    int*                  varsR,              /**< pointer to store variables in R */
2751    int*                  nvarsF,             /**< pointer to store number of variables in F */
2752    int*                  nvarsR              /**< pointer to store number of variables in R */
2753    )
2754 {
2755    int j;
2756 
2757    assert(scip != NULL);
2758    assert(nnoncovervars >= 0);
2759    assert(solvals != NULL);
2760    assert(noncovervars != NULL);
2761    assert(varsF != NULL);
2762    assert(varsR != NULL);
2763    assert(nvarsF != NULL);
2764    assert(nvarsR != NULL);
2765 
2766    *nvarsF = 0;
2767    *nvarsR = 0;
2768 
2769    for( j = 0; j < nnoncovervars; j++ )
2770    {
2771       /* variable has solution value zero */
2772       if( SCIPisFeasEQ(scip, solvals[noncovervars[j]], 0.0) )
2773       {
2774          varsR[*nvarsR] = noncovervars[j];
2775          (*nvarsR)++;
2776       }
2777       /* variable has solution value greater than zero */
2778       else
2779       {
2780          assert(SCIPisFeasGT(scip, solvals[noncovervars[j]], 0.0));
2781          varsF[*nvarsF] = noncovervars[j];
2782          (*nvarsF)++;
2783       }
2784    }
2785    assert((*nvarsF) + (*nvarsR) == nnoncovervars);
2786 }
2787 
2788 /** sorts variables in F, C_2, and R according to the second level lifting sequence that will be used in the sequential
2789  *  lifting procedure
2790  */
2791 static
getLiftingSequence(SCIP * scip,SCIP_Real * solvals,SCIP_Longint * weights,int * varsF,int * varsC2,int * varsR,int nvarsF,int nvarsC2,int nvarsR)2792 SCIP_RETCODE getLiftingSequence(
2793    SCIP*                 scip,               /**< SCIP data structure */
2794    SCIP_Real*            solvals,            /**< solution values of all problem variables */
2795    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
2796    int*                  varsF,              /**< pointer to store variables in F */
2797    int*                  varsC2,             /**< pointer to store variables in C2 */
2798    int*                  varsR,              /**< pointer to store variables in R */
2799    int                   nvarsF,             /**< number of variables in F */
2800    int                   nvarsC2,            /**< number of variables in C2 */
2801    int                   nvarsR              /**< number of variables in R */
2802    )
2803 {
2804    SORTKEYPAIR** sortkeypairsF;
2805    SORTKEYPAIR* sortkeypairsFstore;
2806    SCIP_Real* sortkeysC2;
2807    SCIP_Real* sortkeysR;
2808    int j;
2809 
2810    assert(scip != NULL);
2811    assert(solvals != NULL);
2812    assert(weights != NULL);
2813    assert(varsF != NULL);
2814    assert(varsC2 != NULL);
2815    assert(varsR != NULL);
2816    assert(nvarsF >= 0);
2817    assert(nvarsC2 >= 0);
2818    assert(nvarsR >= 0);
2819 
2820    /* allocates temporary memory */
2821    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsF, nvarsF) );
2822    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsFstore, nvarsF) );
2823    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2824    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2825 
2826    /* gets sorting key for variables in F corresponding to the following lifting sequence
2827     *  sequence 1: non-increasing absolute difference between x*_j and the value the variable is fixed to, i.e.
2828     *              x*_1 >= x*_2 >= ... >= x*_|F|
2829     * in case of equality uses
2830     *  sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2831     */
2832    for( j = 0; j < nvarsF; j++ )
2833    {
2834       sortkeypairsF[j] = &(sortkeypairsFstore[j]);
2835       sortkeypairsF[j]->key1 = solvals[varsF[j]];
2836       sortkeypairsF[j]->key2 = (SCIP_Real) weights[varsF[j]];
2837    }
2838 
2839    /* gets sorting key for variables in C_2 corresponding to the following lifting sequence
2840     *  sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|C_2|
2841     */
2842    for( j = 0; j < nvarsC2; j++ )
2843       sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
2844 
2845    /* gets sorting key for variables in R corresponding to the following lifting sequence
2846     *  sequence 4: non-increasing a_j, i.e. a_1 >= a_2 >= ... >= a_|R|
2847     */
2848    for( j = 0; j < nvarsR; j++ )
2849       sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
2850 
2851    /* sorts F, C2 and R */
2852    if( nvarsF > 0 )
2853    {
2854       SCIPsortDownPtrInt((void**)sortkeypairsF, varsF, compSortkeypairs, nvarsF);
2855    }
2856    if( nvarsC2 > 0 )
2857    {
2858       SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
2859    }
2860    if( nvarsR > 0)
2861    {
2862       SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
2863    }
2864 
2865    /* frees temporary memory */
2866    SCIPfreeBufferArray(scip, &sortkeysR);
2867    SCIPfreeBufferArray(scip, &sortkeysC2);
2868    SCIPfreeBufferArray(scip, &sortkeypairsFstore);
2869    SCIPfreeBufferArray(scip, &sortkeypairsF);
2870 
2871    return SCIP_OKAY;
2872 }
2873 
2874 /** categorizes GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of the GUBs
2875  *  for the sequential GUB wise lifting procedure
2876  */
2877 static
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)2878 SCIP_RETCODE getLiftingSequenceGUB(
2879    SCIP*                 scip,               /**< SCIP data structure */
2880    SCIP_GUBSET*          gubset,             /**< GUB set data structure */
2881    SCIP_Real*            solvals,            /**< solution values of variables in knapsack constraint */
2882    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
2883    int*                  varsC1,             /**< variables in C1 */
2884    int*                  varsC2,             /**< variables in C2 */
2885    int*                  varsF,              /**< variables in F */
2886    int*                  varsR,              /**< variables in R */
2887    int                   nvarsC1,            /**< number of variables in C1 */
2888    int                   nvarsC2,            /**< number of variables in C2 */
2889    int                   nvarsF,             /**< number of variables in F */
2890    int                   nvarsR,             /**< number of variables in R */
2891    int*                  gubconsGC1,         /**< pointer to store GUBs in GC1(GNC1+GOC1) */
2892    int*                  gubconsGC2,         /**< pointer to store GUBs in GC2 */
2893    int*                  gubconsGFC1,        /**< pointer to store GUBs in GFC1(GNC1+GF) */
2894    int*                  gubconsGR,          /**< pointer to store GUBs in GR */
2895    int*                  ngubconsGC1,        /**< pointer to store number of GUBs in GC1(GNC1+GOC1) */
2896    int*                  ngubconsGC2,        /**< pointer to store number of GUBs in GC2 */
2897    int*                  ngubconsGFC1,       /**< pointer to store number of GUBs in GFC1(GNC1+GF) */
2898    int*                  ngubconsGR,         /**< pointer to store number of GUBs in GR */
2899    int*                  ngubconscapexceed,  /**< pointer to store number of GUBs with only capacity exceeding variables */
2900    int*                  maxgubvarssize      /**< pointer to store the maximal size of GUB constraints */
2901    )
2902 {
2903    SORTKEYPAIR** sortkeypairsGFC1;
2904    SORTKEYPAIR* sortkeypairsGFC1store;
2905    SCIP_Real* sortkeysC1;
2906    SCIP_Real* sortkeysC2;
2907    SCIP_Real* sortkeysR;
2908    int* nC1varsingubcons;
2909    int var;
2910    int gubconsidx;
2911    int varidx;
2912    int ngubconss;
2913    int ngubconsGOC1;
2914    int targetvar;
2915    int nvarsprocessed;
2916    int i;
2917    int j;
2918 
2919 #if GUBSPLITGNC1GUBS
2920    SCIP_Bool gubconswithF;
2921    int origngubconss;
2922    origngubconss = gubset->ngubconss;
2923 #endif
2924 
2925    assert(scip != NULL);
2926    assert(gubset != NULL);
2927    assert(solvals != NULL);
2928    assert(weights != NULL);
2929    assert(varsC1 != NULL);
2930    assert(varsC2 != NULL);
2931    assert(varsF != NULL);
2932    assert(varsR != NULL);
2933    assert(nvarsC1 > 0);
2934    assert(nvarsC2 >= 0);
2935    assert(nvarsF >= 0);
2936    assert(nvarsR >= 0);
2937    assert(gubconsGC1 != NULL);
2938    assert(gubconsGC2 != NULL);
2939    assert(gubconsGFC1 != NULL);
2940    assert(gubconsGR != NULL);
2941    assert(ngubconsGC1 != NULL);
2942    assert(ngubconsGC2 != NULL);
2943    assert(ngubconsGFC1 != NULL);
2944    assert(ngubconsGR != NULL);
2945    assert(maxgubvarssize != NULL);
2946 
2947    ngubconss = gubset->ngubconss;
2948    nvarsprocessed = 0;
2949    ngubconsGOC1 = 0;
2950 
2951    /* GUBs are categorized into different types according to the variables in volved
2952     * - GOC1:  involves variables in C1 only           -- no C2, R, F
2953     * - GNC1:  involves variables in C1 and F (and R)  -- no C2
2954     * - GF:    involves variables in F  (and R) only   -- no C1, C2
2955     * - GC2:   involves variables in C2 only           -- no C1, R, F
2956     * - GR:    involves variables in R  only           -- no C1, C2, F
2957     * which requires splitting GUBs in case they include variable in F and R.
2958     *
2959     * afterwards all GUBs (except GOC1 GUBs, which we do not need to lift) are sorted by a two level lifting sequence.
2960     * - first  ordering level is: GFC1 (GNC1+GF), GC2, and GR.
2961     * - second ordering level is
2962     *    GFC1:   non-increasing number of variables in F and non-increasing max{x*_k : k in GFC1_j} in case of equality
2963     *    GC2:    non-increasing max{ a_k : k in GC2_j}; note that |GFC2_j| = 1
2964     *    GR:     non-increasing max{ a_k : k in GR_j}
2965     *
2966     * in additon, another GUB union, which is helpful for the lifting procedure, is formed
2967     * - GC1:   GUBs of category GOC1 and GNC1
2968     * with second ordering level non-decreasing min{ a_k : k in GC1_j };
2969     * note that min{ a_k : k in GC1_j } always comes from the first variable in the GUB
2970     */
2971 
2972    /* allocates temporary memory */
2973    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC1, nvarsC1) );
2974    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysC2, nvarsC2) );
2975    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeysR, nvarsR) );
2976 
2977    /* to get the GUB lifting sequence, we first sort all variables in F, C2, and R
2978     * - F:      non-increasing x*_j and non-increasing a_j in case of equality
2979     * - C2:     non-increasing a_j
2980     * - R:      non-increasing a_j
2981     * furthermore, sort C1 variables as needed for initializing the minweight table (non-increasing a_j).
2982     */
2983 
2984    /* gets sorting key for variables in C1 corresponding to the following ordering
2985     *  non-decreasing a_j, i.e. a_1 <= a_2 <= ... <= a_|C_1|
2986     */
2987    for( j = 0; j < nvarsC1; j++ )
2988    {
2989       /* gets sortkeys */
2990       sortkeysC1[j] = (SCIP_Real) weights[varsC1[j]];
2991 
2992       /* update status of variable in its gub constraint */
2993       gubconsidx = gubset->gubconssidx[varsC1[j]];
2994       varidx = gubset->gubvarsidx[varsC1[j]];
2995       gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C1;
2996    }
2997 
2998    /* gets sorting key for variables in F corresponding to the following ordering
2999     *  non-increasing x*_j, i.e., x*_1 >= x*_2 >= ... >= x*_|F|, and
3000     *  non-increasing a_j,  i.e., a_1  >= a_2  >= ... >= a_|F| in case of equality
3001     * and updates status of each variable in F in GUB set data structure
3002     */
3003    for( j = 0; j < nvarsF; j++ )
3004    {
3005       /* update status of variable in its gub constraint */
3006       gubconsidx = gubset->gubconssidx[varsF[j]];
3007       varidx = gubset->gubvarsidx[varsF[j]];
3008       gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_F;
3009    }
3010 
3011    /* gets sorting key for variables in C2 corresponding to the following ordering
3012     *  non-increasing a_j,  i.e., a_1  >= a_2  >= ... >= a_|C2|
3013     * and updates status of each variable in F in GUB set data structure
3014     */
3015    for( j = 0; j < nvarsC2; j++ )
3016    {
3017       /* gets sortkeys */
3018       sortkeysC2[j] = (SCIP_Real) weights[varsC2[j]];
3019 
3020       /* update status of variable in its gub constraint */
3021       gubconsidx = gubset->gubconssidx[varsC2[j]];
3022       varidx = gubset->gubvarsidx[varsC2[j]];
3023       gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_C2;
3024    }
3025 
3026    /* gets sorting key for variables in R corresponding to the following ordering
3027     *  non-increasing a_j,  i.e., a_1  >= a_2  >= ... >= a_|R|
3028     * and updates status of each variable in F in GUB set data structure
3029     */
3030    for( j = 0; j < nvarsR; j++ )
3031    {
3032       /* gets sortkeys */
3033       sortkeysR[j] = (SCIP_Real) weights[varsR[j]];
3034 
3035       /* update status of variable in its gub constraint */
3036       gubconsidx = gubset->gubconssidx[varsR[j]];
3037       varidx = gubset->gubvarsidx[varsR[j]];
3038       gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] = GUBVARSTATUS_BELONGSTOSET_R;
3039    }
3040 
3041    /* sorts C1, F, C2 and R */
3042    assert(nvarsC1 > 0);
3043    SCIPsortRealInt(sortkeysC1, varsC1, nvarsC1);
3044 
3045    if( nvarsC2 > 0 )
3046    {
3047       SCIPsortDownRealInt(sortkeysC2, varsC2, nvarsC2);
3048    }
3049    if( nvarsR > 0)
3050    {
3051       SCIPsortDownRealInt(sortkeysR, varsR, nvarsR);
3052    }
3053 
3054    /* frees temporary memory */
3055    SCIPfreeBufferArray(scip, &sortkeysR);
3056    SCIPfreeBufferArray(scip, &sortkeysC2);
3057    SCIPfreeBufferArray(scip, &sortkeysC1);
3058 
3059    /* allocate and initialize temporary memory for sorting GUB constraints */
3060    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1, ngubconss) );
3061    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairsGFC1store, ngubconss) );
3062    SCIP_CALL( SCIPallocBufferArray(scip, &nC1varsingubcons, ngubconss) );
3063    BMSclearMemoryArray(nC1varsingubcons, ngubconss);
3064    for( i = 0; i < ngubconss; i++)
3065    {
3066       sortkeypairsGFC1[i] = &(sortkeypairsGFC1store[i]);
3067       sortkeypairsGFC1[i]->key1 = 0.0;
3068       sortkeypairsGFC1[i]->key2 = 0.0;
3069    }
3070    *ngubconsGC1 = 0;
3071    *ngubconsGC2 = 0;
3072    *ngubconsGFC1 = 0;
3073    *ngubconsGR = 0;
3074    *ngubconscapexceed = 0;
3075    *maxgubvarssize = 0;
3076 
3077 #ifndef NDEBUG
3078    for( i = 0; i < gubset->ngubconss; i++ )
3079       assert(gubset->gubconsstatus[i] == GUBCONSSTATUS_UNINITIAL);
3080 #endif
3081 
3082    /* stores GUBs of group GC1 (GOC1+GNC1) and part of the GUBs of group GFC1 (GNC1 GUBs) and sorts variables in these GUBs
3083     * s.t. C1 variables come first (will automatically be sorted by non-decreasing weight).
3084     * gets sorting keys for GUBs of type GFC1 corresponding to the following ordering
3085     *    non-increasing number of variables in F, and
3086     *    non-increasing max{x*_k : k in GFC1_j} in case of equality
3087     */
3088    for( i = 0; i < nvarsC1; i++ )
3089    {
3090       int nvarsC1capexceed;
3091 
3092       nvarsC1capexceed = 0;
3093 
3094       var = varsC1[i];
3095       gubconsidx = gubset->gubconssidx[var];
3096       varidx = gubset->gubvarsidx[var];
3097 
3098       assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3099       assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C1);
3100 
3101       /* current C1 variable is put to the front of its GUB where C1 part is stored by non-decreasing weigth;
3102        * note that variables in C1 are already sorted by non-decreasing weigth
3103        */
3104       targetvar = gubset->gubconss[gubconsidx]->gubvars[nC1varsingubcons[gubconsidx]];
3105       GUBsetSwapVars(scip, gubset, var, targetvar);
3106       nC1varsingubcons[gubconsidx]++;
3107 
3108       /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3109       if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3110       {
3111          assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
3112             || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3113          continue;
3114       }
3115 
3116       /* determine the status of the current GUB constraint, GOC1 or GNC1; GUBs involving R variables are split into
3117        * GOC1/GNC1 and GF, if wanted. also update sorting key if GUB is of type GFC1 (GNC1)
3118        */
3119 #if GUBSPLITGNC1GUBS
3120       gubconswithF = FALSE;
3121 #endif
3122       for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3123       {
3124          assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2);
3125 
3126          /* C1-variable: update number of C1/capacity exceeding variables */
3127          if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_C1 )
3128          {
3129             nvarsC1capexceed++;
3130             nvarsprocessed++;
3131          }
3132          /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3133          else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3134          {
3135 #if GUBSPLITGNC1GUBS
3136 	    gubconswithF = TRUE;
3137 #endif
3138 	    sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3139 
3140             if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3141                sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3142          }
3143          else if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_CAPACITYEXCEEDED )
3144          {
3145             nvarsC1capexceed++;
3146          }
3147          else
3148             assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_R);
3149       }
3150 
3151       /* update set of GC1 GUBs */
3152       gubconsGC1[*ngubconsGC1] = gubconsidx;
3153       (*ngubconsGC1)++;
3154 
3155       /* update maximum size of all GUB constraints */
3156       if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3157 	 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3158 
3159       /* set status of GC1-GUB (GOC1 or GNC1) and update set of GFC1 GUBs */
3160       if( nvarsC1capexceed == gubset->gubconss[gubconsidx]->ngubvars )
3161       {
3162          gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3163 	 ngubconsGOC1++;
3164       }
3165       else
3166       {
3167 #if GUBSPLITGNC1GUBS
3168          /* only variables in C1 and R -- no in F: GUB will be split into GR and GOC1 GUBs */
3169 	 if( !gubconswithF )
3170 	 {
3171 	    GUBVARSTATUS movevarstatus;
3172 
3173 	    assert(gubset->ngubconss < gubset->nvars);
3174 
3175             /* create a new GUB for GR part of splitting */
3176 	    SCIP_CALL( GUBconsCreate(scip, &gubset->gubconss[gubset->ngubconss]) );
3177 	    gubset->ngubconss++;
3178 	    ngubconss = gubset->ngubconss;
3179 
3180             /* fill GR with R variables in current GUB */
3181 	    for( j = gubset->gubconss[gubconsidx]->ngubvars-1; j >= 0; j-- )
3182 	    {
3183 	        movevarstatus = gubset->gubconss[gubconsidx]->gubvarsstatus[j];
3184 		if( movevarstatus != GUBVARSTATUS_BELONGSTOSET_C1 )
3185 		{
3186 		   assert(movevarstatus == GUBVARSTATUS_BELONGSTOSET_R || movevarstatus == GUBVARSTATUS_CAPACITYEXCEEDED);
3187 		   SCIP_CALL( GUBsetMoveVar(scip, gubset, vars, gubset->gubconss[gubconsidx]->gubvars[j],
3188                          gubconsidx, ngubconss-1) );
3189 		   gubset->gubconss[ngubconss-1]->gubvarsstatus[gubset->gubconss[ngubconss-1]->ngubvars-1] =
3190                       movevarstatus;
3191 		}
3192 	    }
3193 
3194 	    gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GOC1;
3195 	    ngubconsGOC1++;
3196 
3197 	    gubset->gubconsstatus[ngubconss-1] = GUBCONSSTATUS_BELONGSTOSET_GR;
3198 	    gubconsGR[*ngubconsGR] = ngubconss-1;
3199 	    (*ngubconsGR)++;
3200 	 }
3201          /* variables in C1, F, and maybe R: GNC1 GUB */
3202 	 else
3203 	 {
3204 	    assert(gubconswithF);
3205 
3206 	    gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3207 	    gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3208 	    (*ngubconsGFC1)++;
3209 	 }
3210 #else
3211 	 gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GNC1;
3212 	 gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3213 	 (*ngubconsGFC1)++;
3214 #endif
3215       }
3216    }
3217 
3218    /* stores GUBs of group GC2 (only trivial GUBs); sorting is not required because the C2 variables (which we loop over)
3219     * are already sorted correctly
3220     */
3221    for( i = 0; i < nvarsC2; i++ )
3222    {
3223       var = varsC2[i];
3224       gubconsidx = gubset->gubconssidx[var];
3225       varidx = gubset->gubvarsidx[var];
3226 
3227       assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3228       assert(gubset->gubconss[gubconsidx]->ngubvars == 1);
3229       assert(varidx == 0);
3230       assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_C2);
3231       assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_UNINITIAL);
3232 
3233       /* set status of GC2 GUB */
3234       gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GC2;
3235 
3236       /* update group of GC2 GUBs */
3237       gubconsGC2[*ngubconsGC2] = gubconsidx;
3238       (*ngubconsGC2)++;
3239 
3240       /* update maximum size of all GUB constraints */
3241       if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3242 	 *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3243 
3244       nvarsprocessed++;
3245    }
3246 
3247    /* stores remaining part of the GUBs of group GFC1 (GF GUBs) and gets GUB sorting keys corresp. to following ordering
3248     *    non-increasing number of variables in F, and
3249     *    non-increasing max{x*_k : k in GFC1_j} in case of equality
3250     */
3251    for( i = 0; i < nvarsF; i++ )
3252    {
3253       var = varsF[i];
3254       gubconsidx = gubset->gubconssidx[var];
3255       varidx = gubset->gubvarsidx[var];
3256 
3257       assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3258       assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_F);
3259 
3260       nvarsprocessed++;
3261 
3262       /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3263       if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3264       {
3265 	 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3266 	      || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3267          continue;
3268       }
3269 
3270       /* set status of GF GUB */
3271       gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GF;
3272 
3273       /* update sorting key of corresponding GFC1 GUB */
3274       for( j = 0; j < gubset->gubconss[gubconsidx]->ngubvars; j++ )
3275       {
3276          assert(gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C2
3277             && gubset->gubconss[gubconsidx]->gubvarsstatus[j] != GUBVARSTATUS_BELONGSTOSET_C1);
3278 
3279          /* F-variable: update sort key (number of F variables in GUB) of corresponding GFC1-GUB */
3280          if( gubset->gubconss[gubconsidx]->gubvarsstatus[j] == GUBVARSTATUS_BELONGSTOSET_F )
3281          {
3282             sortkeypairsGFC1[*ngubconsGFC1]->key1 += 1.0;
3283 
3284             if( solvals[gubset->gubconss[gubconsidx]->gubvars[j]] > sortkeypairsGFC1[*ngubconsGFC1]->key2 )
3285                sortkeypairsGFC1[*ngubconsGFC1]->key2 = solvals[gubset->gubconss[gubconsidx]->gubvars[j]];
3286          }
3287       }
3288 
3289       /* update set of GFC1 GUBs */
3290       gubconsGFC1[*ngubconsGFC1] = gubconsidx;
3291       (*ngubconsGFC1)++;
3292 
3293       /* update maximum size of all GUB constraints */
3294       if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3295          *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3296    }
3297 
3298    /* stores GUBs of group GR; sorting is not required because the R variables (which we loop over) are already sorted
3299     * correctly
3300     */
3301    for( i = 0; i < nvarsR; i++ )
3302    {
3303       var = varsR[i];
3304       gubconsidx = gubset->gubconssidx[var];
3305       varidx = gubset->gubvarsidx[var];
3306 
3307       assert(gubconsidx >= 0 && gubconsidx < ngubconss);
3308       assert(gubset->gubconss[gubconsidx]->gubvarsstatus[varidx] == GUBVARSTATUS_BELONGSTOSET_R);
3309 
3310       nvarsprocessed++;
3311 
3312       /* the GUB was already handled (status set and stored in its group) by another variable of the GUB */
3313       if( gubset->gubconsstatus[gubconsidx] != GUBCONSSTATUS_UNINITIAL )
3314       {
3315 	 assert(gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR
3316 	      || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF
3317 	      || gubset->gubconsstatus[gubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3318          continue;
3319       }
3320 
3321       /* set status of GR GUB */
3322       gubset->gubconsstatus[gubconsidx] = GUBCONSSTATUS_BELONGSTOSET_GR;
3323 
3324       /* update set of GR GUBs */
3325       gubconsGR[*ngubconsGR] = gubconsidx;
3326       (*ngubconsGR)++;
3327 
3328       /* update maximum size of all GUB constraints */
3329       if( gubset->gubconss[gubconsidx]->gubvarssize > *maxgubvarssize )
3330          *maxgubvarssize = gubset->gubconss[gubconsidx]->gubvarssize;
3331    }
3332    assert(nvarsprocessed == nvarsC1 + nvarsC2 + nvarsF + nvarsR);
3333 
3334    /* update number of GUBs with only capacity exceeding variables (will not be used for lifting) */
3335    (*ngubconscapexceed) =  ngubconss - (ngubconsGOC1 + (*ngubconsGC2) + (*ngubconsGFC1) + (*ngubconsGR));
3336    assert(*ngubconscapexceed >= 0);
3337 #ifndef NDEBUG
3338    {
3339       int check;
3340 
3341       check = 0;
3342 
3343       /* remaining not handled GUBs should only contain capacity exceeding variables */
3344       for( i = 0; i < ngubconss; i++ )
3345       {
3346          if( gubset->gubconsstatus[i] ==  GUBCONSSTATUS_UNINITIAL )
3347             check++;
3348       }
3349       assert(check == *ngubconscapexceed);
3350    }
3351 #endif
3352 
3353    /* sort GFCI GUBs according to computed sorting keys */
3354    if( (*ngubconsGFC1) > 0 )
3355    {
3356       SCIPsortDownPtrInt((void**)sortkeypairsGFC1, gubconsGFC1, compSortkeypairs, (*ngubconsGFC1));
3357    }
3358 
3359    /* free temporary memory */
3360 #if GUBSPLITGNC1GUBS
3361    ngubconss = origngubconss;
3362 #endif
3363    SCIPfreeBufferArray(scip, &nC1varsingubcons);
3364    SCIPfreeBufferArray(scip, &sortkeypairsGFC1store);
3365    SCIPfreeBufferArray(scip, &sortkeypairsGFC1);
3366 
3367    return SCIP_OKAY;
3368 }
3369 
3370 /** enlarges minweight table to at least the given length */
3371 static
enlargeMinweights(SCIP * scip,SCIP_Longint ** minweightsptr,int * minweightslen,int * minweightssize,int newlen)3372 SCIP_RETCODE enlargeMinweights(
3373    SCIP*                 scip,               /**< SCIP data structure */
3374    SCIP_Longint**        minweightsptr,      /**< pointer to minweights table */
3375    int*                  minweightslen,      /**< pointer to store number of entries in minweights table (incl. z=0) */
3376    int*                  minweightssize,     /**< pointer to current size of minweights table */
3377    int                   newlen              /**< new length of minweights table */
3378    )
3379 {
3380    int j;
3381 
3382    assert(minweightsptr != NULL);
3383    assert(*minweightsptr != NULL);
3384    assert(minweightslen != NULL);
3385    assert(*minweightslen >= 0);
3386    assert(minweightssize != NULL);
3387    assert(*minweightssize >= 0);
3388 
3389    if( newlen > *minweightssize )
3390    {
3391       int newsize;
3392 
3393       /* reallocate table memory */
3394       newsize = SCIPcalcMemGrowSize(scip, newlen);
3395       SCIP_CALL( SCIPreallocBufferArray(scip, minweightsptr, newsize) );
3396       *minweightssize = newsize;
3397    }
3398    assert(newlen <= *minweightssize);
3399 
3400    /* initialize new elements */
3401    for( j = *minweightslen; j < newlen; ++j )
3402       (*minweightsptr)[j] = SCIP_LONGINT_MAX;
3403    *minweightslen = newlen;
3404 
3405    return SCIP_OKAY;
3406 }
3407 
3408 /** lifts given inequality
3409  *    sum_{j in M_1} x_j <= alpha_0
3410  *  valid for
3411  *    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 }
3412  *  to a valid inequality
3413  *    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
3414  *    <= alpha_0 + sum_{j in M_2} alpha_j
3415  *  for
3416  *    S = { x in {0,1}^|N| : sum_{j in N} a_j x_j <= a_0 };
3417  *  uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in M_2, and
3418  *  sequential up-lifting for the variables in R; procedure can be used to strengthen minimal cover inequalities and
3419  *  extended weight inequalities.
3420  */
3421 static
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)3422 SCIP_RETCODE sequentialUpAndDownLifting(
3423    SCIP*                 scip,               /**< SCIP data structure */
3424    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
3425    int                   nvars,              /**< number of variables in knapsack constraint */
3426    int                   ntightened,         /**< number of variables with tightened upper bound */
3427    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
3428    SCIP_Longint          capacity,           /**< capacity of knapsack */
3429    SCIP_Real*            solvals,            /**< solution values of all problem variables */
3430    int*                  varsM1,             /**< variables in M_1 */
3431    int*                  varsM2,             /**< variables in M_2 */
3432    int*                  varsF,              /**< variables in F */
3433    int*                  varsR,              /**< variables in R */
3434    int                   nvarsM1,            /**< number of variables in M_1 */
3435    int                   nvarsM2,            /**< number of variables in M_2 */
3436    int                   nvarsF,             /**< number of variables in F */
3437    int                   nvarsR,             /**< number of variables in R */
3438    int                   alpha0,             /**< rights hand side of given valid inequality */
3439    int*                  liftcoefs,          /**< pointer to store lifting coefficient of vars in knapsack constraint */
3440    SCIP_Real*            cutact,             /**< pointer to store activity of lifted valid inequality */
3441    int*                  liftrhs             /**< pointer to store right hand side of the lifted valid inequality */
3442    )
3443 {
3444    SCIP_Longint* minweights;
3445    SCIP_Real* sortkeys;
3446    SCIP_Longint fixedonesweight;
3447    int minweightssize;
3448    int minweightslen;
3449    int j;
3450    int w;
3451 
3452    assert(scip != NULL);
3453    assert(vars != NULL);
3454    assert(nvars >= 0);
3455    assert(weights != NULL);
3456    assert(capacity >= 0);
3457    assert(solvals != NULL);
3458    assert(varsM1 != NULL);
3459    assert(varsM2 != NULL);
3460    assert(varsF != NULL);
3461    assert(varsR != NULL);
3462    assert(nvarsM1 >= 0 && nvarsM1 <= nvars - ntightened);
3463    assert(nvarsM2 >= 0 && nvarsM2 <= nvars - ntightened);
3464    assert(nvarsF >= 0 && nvarsF <= nvars - ntightened);
3465    assert(nvarsR >= 0 && nvarsR <= nvars - ntightened);
3466    assert(nvarsM1 + nvarsM2 + nvarsF + nvarsR == nvars  - ntightened);
3467    assert(alpha0 >= 0);
3468    assert(liftcoefs != NULL);
3469    assert(cutact != NULL);
3470    assert(liftrhs != NULL);
3471 
3472    /* allocates temporary memory */
3473    minweightssize = nvarsM1 + 1;
3474    SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3475    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, nvarsM1) );
3476 
3477    /* initializes data structures */
3478    BMSclearMemoryArray(liftcoefs, nvars);
3479    *cutact = 0.0;
3480 
3481    /* sets lifting coefficient of variables in M1, sorts variables in M1 such that a_1 <= a_2 <= ... <= a_|M1|
3482     * and calculates activity of the current valid inequality
3483     */
3484    for( j = 0; j < nvarsM1; j++ )
3485    {
3486       assert(liftcoefs[varsM1[j]] == 0);
3487       liftcoefs[varsM1[j]] = 1;
3488       sortkeys[j] = (SCIP_Real) (weights[varsM1[j]]);
3489       (*cutact) += solvals[varsM1[j]];
3490    }
3491 
3492    SCIPsortRealInt(sortkeys, varsM1, nvarsM1);
3493 
3494    /* initializes (i = 1) the minweight table, defined as: minweights_i[w] =
3495     *   min   sum_{j in M_1} a_j x_j + sum_{k=1}^{i-1} a_{j_k}     x_{j_k}
3496     *   s.t.  sum_{j in M_1}     x_j + sum_{k=1}^{i-1} alpha_{j_k} x_{j_k} >= w
3497     *                                    x_j in {0,1} for j in M_1 & {j_i,...,j_i-1},
3498     * for i = 1,...,t with t = |N\M1| and w = 0,...,|M1| + sum_{k=1}^{i-1} alpha_{j_k};
3499     */
3500    minweights[0] = 0;
3501    for( w = 1; w <= nvarsM1; w++ )
3502       minweights[w] = minweights[w-1] + weights[varsM1[w-1]];
3503    minweightslen = nvarsM1 + 1;
3504 
3505    /* gets sum of weights of variables fixed to one, i.e. sum of weights of variables in M_2 */
3506    fixedonesweight = 0;
3507    for( j = 0; j < nvarsM2; j++ )
3508       fixedonesweight += weights[varsM2[j]];
3509    assert(fixedonesweight >= 0);
3510 
3511    /* initializes right hand side of lifted valid inequality */
3512    *liftrhs = alpha0;
3513 
3514    /* sequentially up-lifts all variables in F: */
3515    for( j = 0; j < nvarsF; j++ )
3516    {
3517       SCIP_Longint weight;
3518       int liftvar;
3519       int liftcoef;
3520       int z;
3521 
3522       liftvar = varsF[j];
3523       weight = weights[liftvar];
3524       assert(liftvar >= 0 && liftvar < nvars);
3525       assert(SCIPisFeasGT(scip, solvals[liftvar], 0.0));
3526       assert(weight > 0);
3527 
3528       /* knapsack problem is infeasible:
3529        *   sets z = 0
3530        */
3531       if( capacity - fixedonesweight - weight < 0 )
3532       {
3533          z = 0;
3534       }
3535       /* knapsack problem is feasible:
3536        *   sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}  } = liftrhs,
3537        *   if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
3538        */
3539       else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
3540       {
3541          z = *liftrhs;
3542       }
3543       /* knapsack problem is feasible:
3544        *   uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i} }
3545        */
3546       else
3547       {
3548          int left;
3549          int right;
3550          int middle;
3551 
3552          assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
3553          left = 0;
3554          right = (*liftrhs) + 1;
3555          while( left < right - 1 )
3556          {
3557             middle = (left + right) / 2;
3558             assert(0 <= middle && middle < minweightslen);
3559             if( minweights[middle] <= capacity - fixedonesweight - weight )
3560                left = middle;
3561             else
3562                right = middle;
3563          }
3564          assert(left == right - 1);
3565          assert(0 <= left && left < minweightslen);
3566          assert(minweights[left] <= capacity - fixedonesweight - weight );
3567          assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
3568 
3569          /* now z = left */
3570          z = left;
3571          assert(z <= *liftrhs);
3572       }
3573 
3574       /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3575       liftcoef = (*liftrhs) - z;
3576       liftcoefs[liftvar] = liftcoef;
3577       assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
3578 
3579       /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3580       if( liftcoef == 0 )
3581          continue;
3582 
3583       /* updates activity of current valid inequality */
3584       (*cutact) += liftcoef * solvals[liftvar];
3585 
3586       /* enlarges current minweight table:
3587        *  from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3588        *  to                  |M1| + sum_{k=1}^{i  } alpha_{j_k} + 1 entries
3589        * and sets minweights_i[w] = infinity for
3590        *  w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3591        */
3592       SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3593 
3594       /* updates minweight table: minweight_i+1[w] =
3595        *   min{ minweights_i[w], a_{j_i}},                                 if w <  alpha_j_i
3596        *   min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i},     if w >= alpha_j_i
3597        */
3598       for( w = minweightslen - 1; w >= 0; w-- )
3599       {
3600          SCIP_Longint min;
3601          if( w < liftcoef )
3602          {
3603             min = MIN(minweights[w], weight);
3604             minweights[w] = min;
3605          }
3606          else
3607          {
3608             assert(w >= liftcoef);
3609             min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3610             minweights[w] = min;
3611          }
3612       }
3613    }
3614    assert(minweights[0] == 0);
3615 
3616    /* sequentially down-lifts all variables in M_2: */
3617    for( j = 0; j < nvarsM2; j++ )
3618    {
3619       SCIP_Longint weight;
3620       int liftvar;
3621       int liftcoef;
3622       int left;
3623       int right;
3624       int middle;
3625       int z;
3626 
3627       liftvar = varsM2[j];
3628       weight = weights[liftvar];
3629       assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
3630       assert(liftvar >= 0 && liftvar < nvars);
3631       assert(weight > 0);
3632 
3633       /* uses binary search to find
3634        *   z = max { w : 0 <= w <= |M_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
3635        */
3636       left = 0;
3637       right = minweightslen;
3638       while( left < right - 1 )
3639       {
3640          middle = (left + right) / 2;
3641          assert(0 <= middle && middle < minweightslen);
3642          if( minweights[middle] <= capacity - fixedonesweight + weight )
3643             left = middle;
3644          else
3645             right = middle;
3646       }
3647       assert(left == right - 1);
3648       assert(0 <= left && left < minweightslen);
3649       assert(minweights[left] <= capacity - fixedonesweight + weight );
3650       assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight + weight);
3651 
3652       /* now z = left */
3653       z = left;
3654       assert(z >= *liftrhs);
3655 
3656       /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
3657       liftcoef = z - (*liftrhs);
3658       liftcoefs[liftvar] = liftcoef;
3659       assert(liftcoef >= 0);
3660 
3661       /* updates sum of weights of variables fixed to one */
3662       fixedonesweight -= weight;
3663 
3664       /* updates right-hand side of current valid inequality */
3665       (*liftrhs) += liftcoef;
3666       assert(*liftrhs >= alpha0);
3667 
3668       /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3669       if( liftcoef == 0 )
3670          continue;
3671 
3672       /* updates activity of current valid inequality */
3673       (*cutact) += liftcoef * solvals[liftvar];
3674 
3675       /* enlarges current minweight table:
3676        *  from minweightlen = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 entries
3677        *  to                  |M1| + sum_{k=1}^{i  } alpha_{j_k} + 1 entries
3678        * and sets minweights_i[w] = infinity for
3679        *  w = |M1| + sum_{k=1}^{i-1} alpha_{j_k} + 1 , ... , |M1| + sum_{k=1}^{i} alpha_{j_k}
3680        */
3681       SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
3682 
3683       /* updates minweight table: minweight_i+1[w] =
3684        *   min{ minweights_i[w], a_{j_i}},                                 if w <  alpha_j_i
3685        *   min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i},     if w >= alpha_j_i
3686        */
3687       for( w = minweightslen - 1; w >= 0; w-- )
3688       {
3689          SCIP_Longint min;
3690          if( w < liftcoef )
3691          {
3692             min = MIN(minweights[w], weight);
3693             minweights[w] = min;
3694          }
3695          else
3696          {
3697             assert(w >= liftcoef);
3698             min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3699             minweights[w] = min;
3700          }
3701       }
3702    }
3703    assert(fixedonesweight == 0);
3704    assert(*liftrhs >= alpha0);
3705 
3706    /* sequentially up-lifts all variables in R: */
3707    for( j = 0; j < nvarsR; j++ )
3708    {
3709       SCIP_Longint weight;
3710       int liftvar;
3711       int liftcoef;
3712       int z;
3713 
3714       liftvar = varsR[j];
3715       weight = weights[liftvar];
3716       assert(liftvar >= 0 && liftvar < nvars);
3717       assert(SCIPisFeasEQ(scip, solvals[liftvar], 0.0));
3718       assert(weight > 0);
3719       assert(capacity - weight >= 0);
3720       assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
3721 
3722       /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
3723        * if minweights_i[liftrhs] <= a_0 - a_{j_i}
3724        */
3725       if( minweights[*liftrhs] <= capacity - weight )
3726       {
3727          z = *liftrhs;
3728       }
3729       /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
3730        */
3731       else
3732       {
3733          int left;
3734          int right;
3735          int middle;
3736 
3737          left = 0;
3738          right = (*liftrhs) + 1;
3739          while( left < right - 1)
3740          {
3741             middle = (left + right) / 2;
3742             assert(0 <= middle && middle < minweightslen);
3743             if( minweights[middle] <= capacity - weight )
3744                left = middle;
3745             else
3746                right = middle;
3747          }
3748          assert(left == right - 1);
3749          assert(0 <= left && left < minweightslen);
3750          assert(minweights[left] <= capacity - weight );
3751          assert(left == minweightslen - 1 || minweights[left+1] > capacity - weight);
3752 
3753          /* now z = left */
3754          z = left;
3755          assert(z <= *liftrhs);
3756       }
3757 
3758       /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
3759       liftcoef = (*liftrhs) - z;
3760       liftcoefs[liftvar] = liftcoef;
3761       assert(liftcoef >= 0 && liftcoef <= *liftrhs);
3762 
3763       /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
3764       if( liftcoef == 0 )
3765          continue;
3766 
3767       /* updates activity of current valid inequality */
3768       (*cutact) += liftcoef * solvals[liftvar];
3769 
3770       /* updates minweight table: minweight_i+1[w] =
3771        *   min{ minweight_i[w], a_{j_i}},                                if w <  alpha_j_i
3772        *   min{ minweight_i[w], minweight_i[w - alpha_j_i] + a_j_i},     if w >= alpha_j_i
3773        */
3774       for( w = *liftrhs; w >= 0; w-- )
3775       {
3776          SCIP_Longint min;
3777          if( w < liftcoef )
3778          {
3779             min = MIN(minweights[w], weight);
3780             minweights[w] = min;
3781          }
3782          else
3783          {
3784             assert(w >= liftcoef);
3785             min = MIN(minweights[w], minweights[w - liftcoef] + weight);
3786             minweights[w] = min;
3787          }
3788       }
3789    }
3790 
3791    /* frees temporary memory */
3792    SCIPfreeBufferArray(scip, &sortkeys);
3793    SCIPfreeBufferArray(scip, &minweights);
3794 
3795    return SCIP_OKAY;
3796 }
3797 
3798 /** adds two minweight values in a safe way, i.e,, ensures no overflow */
3799 static
safeAddMinweightsGUB(SCIP_Longint val1,SCIP_Longint val2)3800 SCIP_Longint safeAddMinweightsGUB(
3801    SCIP_Longint          val1,               /**< first value to add */
3802    SCIP_Longint          val2                /**< second value to add */
3803    )
3804 {
3805    assert(val1 >= 0);
3806    assert(val2 >= 0);
3807 
3808    if( val1 >= SCIP_LONGINT_MAX || val2 >= SCIP_LONGINT_MAX )
3809       return SCIP_LONGINT_MAX;
3810    else
3811    {
3812       assert(val1 <= SCIP_LONGINT_MAX - val2);
3813       return (val1 + val2);
3814    }
3815 }
3816 
3817 /** computes minweights table for lifting with GUBs by combining unfished and fished tables */
3818 static
computeMinweightsGUB(SCIP_Longint * minweights,SCIP_Longint * finished,SCIP_Longint * unfinished,int minweightslen)3819 void computeMinweightsGUB(
3820    SCIP_Longint*         minweights,         /**< minweight table to compute */
3821    SCIP_Longint*         finished,           /**< given finished table */
3822    SCIP_Longint*         unfinished,         /**< given unfinished table */
3823    int                   minweightslen       /**< length of minweight, finished, and unfinished tables */
3824    )
3825 {
3826    int w1;
3827    int w2;
3828 
3829    /* minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
3830     * note that finished and unfished arrays sorted by non-decreasing weight
3831     */
3832 
3833    /* initialize minweight with w2 = 0 */
3834    w2 = 0;
3835    assert(unfinished[w2] == 0);
3836    for( w1 = 0; w1 < minweightslen; w1++ )
3837       minweights[w1] = finished[w1];
3838 
3839    /* consider w2 = 1, ..., minweightslen-1 */
3840    for( w2 = 1; w2 < minweightslen; w2++ )
3841    {
3842       if( unfinished[w2] >= SCIP_LONGINT_MAX )
3843          break;
3844 
3845       for( w1 = 0; w1 < minweightslen - w2; w1++ )
3846       {
3847          SCIP_Longint temp;
3848 
3849 	 temp = safeAddMinweightsGUB(finished[w1], unfinished[w2]);
3850 	 if( temp <= minweights[w1+w2] )
3851 	    minweights[w1+w2] = temp;
3852       }
3853    }
3854 }
3855 
3856 /** lifts given inequality
3857  *    sum_{j in C_1} x_j <= alpha_0
3858  *  valid for
3859  *    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;
3860  *                               sum_{j in Q_i} x_j <= 1, forall i in I }
3861  *  to a valid inequality
3862  *    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
3863  *    <= alpha_0 + sum_{j in C_2} alpha_j
3864  *  for
3865  *    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 };
3866  *  uses sequential up-lifting   for the variables in GUB constraints in gubconsGFC1,
3867  *       sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
3868  *       sequential up-lifting   for the variabels in GUB constraints in gubconsGR.
3869  */
3870 static
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)3871 SCIP_RETCODE sequentialUpAndDownLiftingGUB(
3872    SCIP*                 scip,               /**< SCIP data structure */
3873    SCIP_GUBSET*          gubset,             /**< GUB set data structure */
3874    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
3875    int                   ngubconscapexceed,  /**< number of GUBs with only capacity exceeding variables */
3876    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
3877    SCIP_Longint          capacity,           /**< capacity of knapsack */
3878    SCIP_Real*            solvals,            /**< solution values of all knapsack variables */
3879    int*                  gubconsGC1,         /**< GUBs in GC1(GNC1+GOC1) */
3880    int*                  gubconsGC2,         /**< GUBs in GC2 */
3881    int*                  gubconsGFC1,        /**< GUBs in GFC1(GNC1+GF) */
3882    int*                  gubconsGR,          /**< GUBs in GR */
3883    int                   ngubconsGC1,        /**< number of GUBs in GC1(GNC1+GOC1) */
3884    int                   ngubconsGC2,        /**< number of GUBs in GC2 */
3885    int                   ngubconsGFC1,       /**< number of GUBs in GFC1(GNC1+GF) */
3886    int                   ngubconsGR,         /**< number of GUBs in GR */
3887    int                   alpha0,             /**< rights hand side of given valid inequality */
3888    int*                  liftcoefs,          /**< pointer to store lifting coefficient of vars in knapsack constraint */
3889    SCIP_Real*            cutact,             /**< pointer to store activity of lifted valid inequality */
3890    int*                  liftrhs,            /**< pointer to store right hand side of the lifted valid inequality */
3891    int                   maxgubvarssize      /**< maximal size of GUB constraints */
3892    )
3893 {
3894    SCIP_Longint* minweights;
3895    SCIP_Longint* finished;
3896    SCIP_Longint* unfinished;
3897    int* gubconsGOC1;
3898    int* gubconsGNC1;
3899    int* liftgubvars;
3900    SCIP_Longint fixedonesweight;
3901    SCIP_Longint weight;
3902    SCIP_Longint weightdiff1;
3903    SCIP_Longint weightdiff2;
3904    SCIP_Longint min;
3905    int minweightssize;
3906    int minweightslen;
3907    int nvars;
3908    int varidx;
3909    int liftgubconsidx;
3910    int liftvar;
3911    int sumliftcoef;
3912    int liftcoef;
3913    int ngubconsGOC1;
3914    int ngubconsGNC1;
3915    int left;
3916    int right;
3917    int middle;
3918    int nliftgubvars;
3919    int tmplen;
3920    int tmpsize;
3921    int j;
3922    int k;
3923    int w;
3924    int z;
3925 #ifndef NDEBUG
3926    int ngubconss;
3927    int nliftgubC1;
3928 
3929    assert(gubset != NULL);
3930    ngubconss = gubset->ngubconss;
3931 #else
3932    assert(gubset != NULL);
3933 #endif
3934 
3935    nvars = gubset->nvars;
3936 
3937    assert(scip != NULL);
3938    assert(vars != NULL);
3939    assert(nvars >= 0);
3940    assert(weights != NULL);
3941    assert(capacity >= 0);
3942    assert(solvals != NULL);
3943    assert(gubconsGC1 != NULL);
3944    assert(gubconsGC2 != NULL);
3945    assert(gubconsGFC1 != NULL);
3946    assert(gubconsGR != NULL);
3947    assert(ngubconsGC1 >= 0 && ngubconsGC1 <= ngubconss - ngubconscapexceed);
3948    assert(ngubconsGC2 >= 0 && ngubconsGC2 <= ngubconss - ngubconscapexceed);
3949    assert(ngubconsGFC1 >= 0 && ngubconsGFC1 <= ngubconss - ngubconscapexceed);
3950    assert(ngubconsGR >= 0 && ngubconsGR <= ngubconss - ngubconscapexceed);
3951    assert(alpha0 >= 0);
3952    assert(liftcoefs != NULL);
3953    assert(cutact != NULL);
3954    assert(liftrhs != NULL);
3955 
3956    minweightssize = ngubconsGC1+1;
3957 
3958    /* allocates temporary memory */
3959    SCIP_CALL( SCIPallocBufferArray(scip, &liftgubvars, maxgubvarssize) );
3960    SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGOC1, ngubconsGC1) );
3961    SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGNC1, ngubconsGC1) );
3962    SCIP_CALL( SCIPallocBufferArray(scip, &minweights, minweightssize) );
3963    SCIP_CALL( SCIPallocBufferArray(scip, &finished, minweightssize) );
3964    SCIP_CALL( SCIPallocBufferArray(scip, &unfinished, minweightssize) );
3965 
3966    /* initializes data structures */
3967    BMSclearMemoryArray(liftcoefs, nvars);
3968    *cutact = 0.0;
3969 
3970    /* gets GOC1 and GNC1 GUBs, sets lifting coefficient of variables in C1 and calculates activity of the current
3971     * valid inequality
3972     */
3973    ngubconsGOC1 = 0;
3974    ngubconsGNC1 = 0;
3975    for( j = 0; j < ngubconsGC1; j++ )
3976    {
3977       if( gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GOC1 )
3978       {
3979          gubconsGOC1[ngubconsGOC1] = gubconsGC1[j];
3980          ngubconsGOC1++;
3981       }
3982       else
3983       {
3984          assert(gubset->gubconsstatus[gubconsGC1[j]] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
3985          gubconsGNC1[ngubconsGNC1] = gubconsGC1[j];
3986          ngubconsGNC1++;
3987       }
3988       for( k = 0; k < gubset->gubconss[gubconsGC1[j]]->ngubvars
3989               && gubset->gubconss[gubconsGC1[j]]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
3990       {
3991          varidx = gubset->gubconss[gubconsGC1[j]]->gubvars[k];
3992          assert(varidx >= 0 && varidx < nvars);
3993          assert(liftcoefs[varidx] == 0);
3994 
3995          liftcoefs[varidx] = 1;
3996          (*cutact) += solvals[varidx];
3997       }
3998       assert(k >= 1);
3999    }
4000    assert(ngubconsGOC1 + ngubconsGFC1 + ngubconsGC2 + ngubconsGR == ngubconss - ngubconscapexceed);
4001    assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4002 
4003    /* initialize the minweight tables, defined as: for i = 1,...,m with m = |I| and w = 0,...,|gubconsGC1|;
4004     * - finished_i[w] =
4005     *   min   sum_{k = 1,2,...,i-1} sum_{j in Q_k} a_j x_j
4006     *   s.t.  sum_{k = 1,2,...,i-1} sum_{j in Q_k} alpha_j x_j  >= w
4007     *                               sum_{j in Q_k} x_j <= 1
4008     *                               x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4009     * - unfinished_i[w] =
4010     *   min   sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} a_j x_j
4011     *   s.t.  sum_{k = i+1,...,m} sum_{j in Q_k && j in C1} x_j  >= w
4012     *                             sum_{j in Q_k} x_j <= 1
4013     *                             x_j in {0,1} forall j in Q_k forall k = 1,2,...,i-1,
4014     * - minweights_i[w] = min{finished_i[w1] + unfinished_i[w2] : w1>=0, w2>=0, w1+w2=w};
4015     */
4016 
4017    /* initialize finished table; note that variables in GOC1 GUBs (includes C1 and capacity exceeding variables)
4018     * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4019     * 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
4020     * comes from the first variable in the GUB
4021     */
4022    assert(ngubconsGOC1 <= ngubconsGC1);
4023    finished[0] = 0;
4024    for( w = 1; w <= ngubconsGOC1; w++ )
4025    {
4026       liftgubconsidx = gubconsGOC1[w-1];
4027 
4028       assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1);
4029       assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4030 
4031       varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4032 
4033       assert(varidx >= 0 && varidx < nvars);
4034       assert(liftcoefs[varidx] == 1);
4035 
4036       min = weights[varidx];
4037       finished[w] = finished[w-1] + min;
4038 
4039 #ifndef NDEBUG
4040       for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4041               && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4042       {
4043          varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4044          assert(varidx >= 0 && varidx < nvars);
4045          assert(liftcoefs[varidx] == 1);
4046          assert(weights[varidx] >= min);
4047       }
4048 #endif
4049    }
4050    for( w = ngubconsGOC1+1; w <= ngubconsGC1; w++ )
4051       finished[w] = SCIP_LONGINT_MAX;
4052 
4053    /* initialize unfinished table; note that variables in GNC1 GUBs
4054     * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4055     * 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
4056     * comes from the first variable in the GUB
4057     */
4058    assert(ngubconsGNC1 <= ngubconsGC1);
4059    unfinished[0] = 0;
4060    for( w = 1; w <= ngubconsGNC1; w++ )
4061    {
4062       liftgubconsidx = gubconsGNC1[w-1];
4063 
4064       assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4065       assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4066 
4067       varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4068 
4069       assert(varidx >= 0 && varidx < nvars);
4070       assert(liftcoefs[varidx] == 1);
4071 
4072       min = weights[varidx];
4073       unfinished[w] = unfinished[w-1] + min;
4074 
4075 #ifndef NDEBUG
4076       for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4077               && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4078       {
4079          varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4080          assert(varidx >= 0 && varidx < nvars);
4081          assert(liftcoefs[varidx] == 1);
4082          assert(weights[varidx] >= min );
4083       }
4084 #endif
4085    }
4086    for( w = ngubconsGNC1 + 1; w <= ngubconsGC1; w++ )
4087       unfinished[w] = SCIP_LONGINT_MAX;
4088 
4089    /* initialize minweights table; note that variables in GC1 GUBs
4090     * are sorted s.t. C1 variables come first and are sorted by non-decreasing weight.
4091     * we can directly initialize minweights instead of computing it from finished and unfinished (which would be more time
4092     * consuming) because is it has to be build using weights from C1 only.
4093     */
4094    assert(ngubconsGOC1 + ngubconsGNC1 == ngubconsGC1);
4095    minweights[0] = 0;
4096    for( w = 1; w <= ngubconsGC1; w++ )
4097    {
4098       liftgubconsidx = gubconsGC1[w-1];
4099 
4100       assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GOC1
4101           || gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4102       assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4103 
4104       varidx = gubset->gubconss[liftgubconsidx]->gubvars[0];
4105 
4106       assert(varidx >= 0 && varidx < nvars);
4107       assert(liftcoefs[varidx] == 1);
4108 
4109       min = weights[varidx];
4110       minweights[w] = minweights[w-1] + min;
4111 
4112 #ifndef NDEBUG
4113       for( k = 1; k < gubset->gubconss[liftgubconsidx]->ngubvars
4114               && gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4115       {
4116          varidx = gubset->gubconss[liftgubconsidx]->gubvars[k];
4117          assert(varidx >= 0 && varidx < nvars);
4118          assert(liftcoefs[varidx] == 1);
4119          assert(weights[varidx] >= min);
4120       }
4121 #endif
4122    }
4123    minweightslen = ngubconsGC1 + 1;
4124 
4125    /* gets sum of weights of variables fixed to one, i.e. sum of weights of C2 variables GC2 GUBs */
4126    fixedonesweight = 0;
4127    for( j = 0; j < ngubconsGC2; j++ )
4128    {
4129       varidx = gubset->gubconss[gubconsGC2[j]]->gubvars[0];
4130 
4131       assert(gubset->gubconss[gubconsGC2[j]]->ngubvars == 1);
4132       assert(varidx >= 0 && varidx < nvars);
4133       assert(gubset->gubconss[gubconsGC2[j]]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4134 
4135       fixedonesweight += weights[varidx];
4136    }
4137    assert(fixedonesweight >= 0);
4138 
4139    /* initializes right hand side of lifted valid inequality */
4140    *liftrhs = alpha0;
4141 
4142    /* sequentially up-lifts all variables in GFC1 GUBs */
4143    for( j = 0; j < ngubconsGFC1; j++ )
4144    {
4145       liftgubconsidx = gubconsGFC1[j];
4146       assert(liftgubconsidx >= 0 && liftgubconsidx < ngubconss);
4147 
4148       /* GNC1 GUB: update unfinished table (remove current GUB, i.e., remove min weight of C1 vars in GUB) and
4149        * compute minweight table via updated unfinished table and aleady upto date finished table;
4150        */
4151       k = 0;
4152       if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4153       {
4154 	 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1);
4155          assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C1);
4156          assert(ngubconsGNC1 > 0);
4157 
4158          /* get number of C1 variables of current GNC1 GUB and put them into array of variables in GUB that
4159           * are considered for the lifting, i.e., not capacity exceeding
4160           */
4161          for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars
4162 		&& gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_C1; k++ )
4163             liftgubvars[k] = gubset->gubconss[liftgubconsidx]->gubvars[k];
4164          assert(k >= 1);
4165 
4166          /* update unfinished table by removing current GNC1 GUB, i.e, remove C1 variable with minimal weight
4167 	  * unfinished[w] = MAX{unfinished[w], unfinished[w+1] - weight}, "weight" is the minimal weight of current GUB
4168 	  */
4169          weight = weights[liftgubvars[0]];
4170 
4171 	 weightdiff2 = unfinished[ngubconsGNC1] - weight;
4172 	 unfinished[ngubconsGNC1] = SCIP_LONGINT_MAX;
4173          for( w = ngubconsGNC1-1; w >= 1; w-- )
4174          {
4175 	    weightdiff1 = weightdiff2;
4176 	    weightdiff2 = unfinished[w] - weight;
4177 
4178             if( unfinished[w] < weightdiff1 )
4179 	       unfinished[w] = weightdiff1;
4180 	    else
4181 	       break;
4182          }
4183          ngubconsGNC1--;
4184 
4185          /* computes minweights table by combining unfished and fished tables */
4186          computeMinweightsGUB(minweights, finished, unfinished, minweightslen);
4187          assert(minweights[0] == 0);
4188       }
4189       /* GF GUB: no update of unfinished table (and minweight table) required because GF GUBs have no C1 variables and
4190        * are therefore not in the unfinished table
4191        */
4192       else
4193 	 assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4194 
4195 #ifndef NDEBUG
4196       nliftgubC1 = k;
4197 #endif
4198       nliftgubvars = k;
4199       sumliftcoef = 0;
4200 
4201       /* compute lifting coefficient of F and R variables in GNC1 and GF GUBs (C1 vars have already liftcoef 1) */
4202       for( ; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4203       {
4204          if( gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_F
4205              || gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4206          {
4207             liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4208             weight = weights[liftvar];
4209             assert(weight > 0);
4210             assert(liftvar >= 0 && liftvar < nvars);
4211 	    assert(capacity - weight >= 0);
4212 
4213             /* put variable into array of variables in GUB that are considered for the lifting,
4214              *  i.e., not capacity exceeding
4215              */
4216             liftgubvars[nliftgubvars] = liftvar;
4217             nliftgubvars++;
4218 
4219 	    /* knapsack problem is infeasible:
4220              * sets z = 0
4221              */
4222             if( capacity - fixedonesweight - weight < 0 )
4223             {
4224                z = 0;
4225             }
4226             /* knapsack problem is feasible:
4227              *   sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}  } = liftrhs,
4228              *   if minweights_i[liftrhs] <= a_0 - fixedonesweight - a_{j_i}
4229              */
4230             else if( minweights[*liftrhs] <= capacity - fixedonesweight - weight )
4231             {
4232                z = *liftrhs;
4233             }
4234             /* knapsack problem is feasible:
4235              *   binary search to find z = max {w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - fixedonesweight - a_{j_i}}
4236              */
4237             else
4238             {
4239                assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - fixedonesweight - weight);
4240                left = 0;
4241                right = (*liftrhs) + 1;
4242                while( left < right - 1 )
4243                {
4244                   middle = (left + right) / 2;
4245                   assert(0 <= middle && middle < minweightslen);
4246                   if( minweights[middle] <= capacity - fixedonesweight - weight )
4247                      left = middle;
4248                   else
4249                      right = middle;
4250                }
4251                assert(left == right - 1);
4252                assert(0 <= left && left < minweightslen);
4253                assert(minweights[left] <= capacity - fixedonesweight - weight);
4254                assert(left == minweightslen - 1 || minweights[left+1] > capacity - fixedonesweight - weight);
4255 
4256                /* now z = left */
4257                z = left;
4258                assert(z <= *liftrhs);
4259             }
4260 
4261             /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4262             liftcoef = (*liftrhs) - z;
4263             liftcoefs[liftvar] = liftcoef;
4264             assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4265 
4266 	    /* updates activity of current valid inequality */
4267             (*cutact) += liftcoef * solvals[liftvar];
4268 
4269             /* updates sum of all lifting coefficients in GUB */
4270             sumliftcoef += liftcoefs[liftvar];
4271 	 }
4272          else
4273             assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4274       }
4275       /* at least one variable is in F or R (j = number of C1 variables in current GUB) */
4276       assert(nliftgubvars > nliftgubC1);
4277 
4278       /* activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0
4279        * and finished and minweight table can be updated easily as only C1 variables need to be considered;
4280        * not needed for GF GUBs
4281        */
4282       if( sumliftcoef == 0 )
4283       {
4284 	 if( gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GNC1 )
4285 	 {
4286             weight = weights[liftgubvars[0]];
4287             /* update finished table and minweights table by applying special case of
4288              * finished[w] = MIN{finished[w], finished[w-1] + weight}, "weight" is the minimal weight of current GUB
4289 	     * minweights[w] = MIN{minweights[w], minweights[w-1] + weight}, "weight" is the minimal weight of current GUB
4290              */
4291             for( w = minweightslen-1; w >= 1; w-- )
4292             {
4293                SCIP_Longint tmpval;
4294 
4295                tmpval = safeAddMinweightsGUB(finished[w-1], weight);
4296                finished[w] = MIN(finished[w], tmpval);
4297 
4298                tmpval = safeAddMinweightsGUB(minweights[w-1], weight);
4299                minweights[w] = MIN(minweights[w], tmpval);
4300             }
4301          }
4302          else
4303 	    assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GF);
4304 
4305          continue;
4306       }
4307 
4308       /* enlarges current minweights tables(finished, unfinished, minweights):
4309        *  from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4310        *  to                  |gubconsGC1| + sum_{k=1,2,...,i  }sum_{j in Q_k} alpha_j + 1 entries
4311        *  and sets minweights_i[w] = infinity for
4312        *  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
4313        */
4314       tmplen = minweightslen; /* will be updated in enlargeMinweights() */
4315       tmpsize = minweightssize;
4316       SCIP_CALL( enlargeMinweights(scip, &unfinished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4317       tmplen = minweightslen;
4318       tmpsize = minweightssize;
4319       SCIP_CALL( enlargeMinweights(scip, &finished, &tmplen, &tmpsize, tmplen + sumliftcoef) );
4320       SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + sumliftcoef) );
4321 
4322       /* update finished table and minweight table;
4323        * note that instead of computing minweight table from updated finished and updated unfinished table again
4324        * (for the lifting coefficient, we had to update unfinished table and compute minweight table), we here
4325        * only need to update the minweight table and the updated finished in the same way (i.e., computing for minweight
4326        * not needed because only finished table changed at this point and the change was "adding" one weight)
4327        *
4328        * update formular for minweight table is: minweight_i+1[w] =
4329        *   min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4330        * formular for finished table has the same pattern.
4331        */
4332       for( w = minweightslen-1; w >= 0; w-- )
4333       {
4334          SCIP_Longint minminweight;
4335          SCIP_Longint minfinished;
4336 
4337          for( k = 0; k < nliftgubvars; k++ )
4338 	 {
4339 	    liftcoef = liftcoefs[liftgubvars[k]];
4340 	    weight = weights[liftgubvars[k]];
4341 
4342             if( w < liftcoef )
4343             {
4344 	       minfinished = MIN(finished[w], weight);
4345 	       minminweight = MIN(minweights[w], weight);
4346 
4347                finished[w] = minfinished;
4348                minweights[w] = minminweight;
4349             }
4350             else
4351             {
4352                SCIP_Longint tmpval;
4353 
4354                assert(w >= liftcoef);
4355 
4356                tmpval = safeAddMinweightsGUB(finished[w-liftcoef], weight);
4357                minfinished = MIN(finished[w], tmpval);
4358 
4359                tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4360                minminweight = MIN(minweights[w], tmpval);
4361 
4362                finished[w] = minfinished;
4363                minweights[w] = minminweight;
4364             }
4365 	 }
4366       }
4367       assert(minweights[0] == 0);
4368    }
4369    assert(ngubconsGNC1 == 0);
4370 
4371    /* note: now the unfinished table no longer exists, i.e., it is "0, MAX, MAX, ..." and minweight equals to finished;
4372     * therefore, only work with minweight table from here on
4373     */
4374 
4375    /* sequentially down-lifts C2 variables contained in trivial GC2 GUBs */
4376    for( j = 0; j < ngubconsGC2; j++ )
4377    {
4378       liftgubconsidx = gubconsGC2[j];
4379 
4380       assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4381       assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GC2);
4382       assert(gubset->gubconss[liftgubconsidx]->ngubvars == 1);
4383       assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[0] == GUBVARSTATUS_BELONGSTOSET_C2);
4384 
4385       liftvar = gubset->gubconss[liftgubconsidx]->gubvars[0]; /* C2 GUBs contain only one variable */
4386       weight = weights[liftvar];
4387 
4388       assert(liftvar >= 0 && liftvar < nvars);
4389       assert(SCIPisFeasEQ(scip, solvals[liftvar], 1.0));
4390       assert(weight > 0);
4391 
4392       /* uses binary search to find
4393        *   z = max { w : 0 <= w <= |C_1| + sum_{k=1}^{i-1} alpha_{j_k}, minweights_[w] <= a_0 - fixedonesweight + a_{j_i}}
4394        */
4395       left = 0;
4396       right = minweightslen;
4397       while( left < right - 1 )
4398       {
4399          middle = (left + right) / 2;
4400          assert(0 <= middle && middle < minweightslen);
4401          if( minweights[middle] <= capacity - fixedonesweight + weight )
4402             left = middle;
4403          else
4404             right = middle;
4405       }
4406       assert(left == right - 1);
4407       assert(0 <= left && left < minweightslen);
4408       assert(minweights[left] <= capacity - fixedonesweight + weight);
4409       assert(left == minweightslen - 1 || minweights[left + 1] > capacity - fixedonesweight + weight);
4410 
4411       /* now z = left */
4412       z = left;
4413       assert(z >= *liftrhs);
4414 
4415       /* calculates lifting coefficients alpha_{j_i} = z - liftrhs */
4416       liftcoef = z - (*liftrhs);
4417       liftcoefs[liftvar] = liftcoef;
4418       assert(liftcoef >= 0);
4419 
4420       /* updates sum of weights of variables fixed to one */
4421       fixedonesweight -= weight;
4422 
4423       /* updates right-hand side of current valid inequality */
4424       (*liftrhs) += liftcoef;
4425       assert(*liftrhs >= alpha0);
4426 
4427       /* minweight table and activity of current valid inequality will not change, if alpha_{j_i} = 0 */
4428       if( liftcoef == 0 )
4429 	 continue;
4430 
4431       /* updates activity of current valid inequality */
4432       (*cutact) += liftcoef * solvals[liftvar];
4433 
4434       /* enlarges current minweight table:
4435        *  from minweightlen = |gubconsGC1| + sum_{k=1,2,...,i-1}sum_{j in Q_k} alpha_j + 1 entries
4436        *  to                  |gubconsGC1| + sum_{k=1,2,...,i  }sum_{j in Q_k} alpha_j + 1 entries
4437        * and sets minweights_i[w] = infinity for
4438        *  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
4439        */
4440       SCIP_CALL( enlargeMinweights(scip, &minweights, &minweightslen, &minweightssize, minweightslen + liftcoef) );
4441 
4442       /* updates minweight table: minweight_i+1[w] =
4443        *  min{ minweights_i[w], a_{j_i}},                                 if w <  alpha_j_i
4444        *  min{ minweights_i[w], minweights_i[w - alpha_j_i] + a_j_i},     if w >= alpha_j_i
4445        */
4446       for( w = minweightslen - 1; w >= 0; w-- )
4447       {
4448          if( w < liftcoef )
4449          {
4450             min = MIN(minweights[w], weight);
4451             minweights[w] = min;
4452          }
4453          else
4454          {
4455             SCIP_Longint tmpval;
4456 
4457             assert(w >= liftcoef);
4458 
4459             tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4460             min = MIN(minweights[w], tmpval);
4461             minweights[w] = min;
4462          }
4463       }
4464    }
4465    assert(fixedonesweight == 0);
4466    assert(*liftrhs >= alpha0);
4467 
4468    /* sequentially up-lifts variables in GUB constraints in GR GUBs */
4469    for( j = 0; j < ngubconsGR; j++ )
4470    {
4471       liftgubconsidx = gubconsGR[j];
4472 
4473       assert(liftgubconsidx >=0 && liftgubconsidx < ngubconss);
4474       assert(gubset->gubconsstatus[liftgubconsidx] == GUBCONSSTATUS_BELONGSTOSET_GR);
4475 
4476       sumliftcoef = 0;
4477       nliftgubvars = 0;
4478       for( k = 0; k < gubset->gubconss[liftgubconsidx]->ngubvars; k++ )
4479       {
4480          if(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_BELONGSTOSET_R )
4481          {
4482             liftvar = gubset->gubconss[liftgubconsidx]->gubvars[k];
4483             weight = weights[liftvar];
4484             assert(weight > 0);
4485             assert(liftvar >= 0 && liftvar < nvars);
4486 	    assert(capacity - weight >= 0);
4487             assert((*liftrhs) + 1 >= minweightslen || minweights[(*liftrhs) + 1] > capacity - weight);
4488 
4489             /* put variable into array of variables in GUB that are considered for the lifting,
4490              *  i.e., not capacity exceeding
4491              */
4492 	    liftgubvars[nliftgubvars] = liftvar;
4493             nliftgubvars++;
4494 
4495             /* sets z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} } = liftrhs,
4496              * if minweights_i[liftrhs] <= a_0 - a_{j_i}
4497              */
4498             if( minweights[*liftrhs] <= capacity - weight )
4499             {
4500                z = *liftrhs;
4501             }
4502             /* uses binary search to find z = max { w : 0 <= w <= liftrhs, minweights_i[w] <= a_0 - a_{j_i} }
4503              */
4504             else
4505             {
4506                left = 0;
4507                right = (*liftrhs) + 1;
4508                while( left < right - 1 )
4509                {
4510                   middle = (left + right) / 2;
4511                   assert(0 <= middle && middle < minweightslen);
4512                   if( minweights[middle] <= capacity - weight )
4513                      left = middle;
4514                   else
4515                      right = middle;
4516                }
4517                assert(left == right - 1);
4518                assert(0 <= left && left < minweightslen);
4519                assert(minweights[left] <= capacity - weight);
4520                assert(left == minweightslen - 1 || minweights[left + 1] > capacity - weight);
4521 
4522                /* now z = left */
4523                z = left;
4524                assert(z <= *liftrhs);
4525             }
4526             /* calculates lifting coefficients alpha_{j_i} = liftrhs - z */
4527             liftcoef = (*liftrhs) - z;
4528             liftcoefs[liftvar] = liftcoef;
4529             assert(liftcoef >= 0 && liftcoef <= (*liftrhs) + 1);
4530 
4531             /* updates activity of current valid inequality */
4532             (*cutact) += liftcoef * solvals[liftvar];
4533 
4534             /* updates sum of all lifting coefficients in GUB */
4535             sumliftcoef += liftcoefs[liftvar];
4536          }
4537          else
4538             assert(gubset->gubconss[liftgubconsidx]->gubvarsstatus[k] == GUBVARSTATUS_CAPACITYEXCEEDED);
4539       }
4540       assert(nliftgubvars >= 1); /* at least one variable is in R */
4541 
4542       /* minweight table and activity of current valid inequality will not change if (sum of alpha_{j_i} in GUB) = 0 */
4543       if( sumliftcoef == 0 )
4544 	 continue;
4545 
4546       /* updates minweight table: minweight_i+1[w] =
4547        *   min{ minweights_i[w], min{ minweights_i[w - alpha_k]^{+} + a_k : k in GUB_j_i } }
4548        */
4549       for( w = *liftrhs; w >= 0; w-- )
4550       {
4551          for( k = 0; k < nliftgubvars; k++ )
4552          {
4553             liftcoef = liftcoefs[liftgubvars[k]];
4554             weight = weights[liftgubvars[k]];
4555 
4556             if( w < liftcoef )
4557             {
4558                min = MIN(minweights[w], weight);
4559                minweights[w] = min;
4560             }
4561             else
4562             {
4563                SCIP_Longint tmpval;
4564 
4565                assert(w >= liftcoef);
4566 
4567                tmpval = safeAddMinweightsGUB(minweights[w-liftcoef], weight);
4568                min = MIN(minweights[w], tmpval);
4569                minweights[w] = min;
4570             }
4571          }
4572       }
4573       assert(minweights[0] == 0);
4574    }
4575 
4576    /* frees temporary memory */
4577    SCIPfreeBufferArray(scip, &minweights);
4578    SCIPfreeBufferArray(scip, &finished);
4579    SCIPfreeBufferArray(scip, &unfinished);
4580    SCIPfreeBufferArray(scip, &liftgubvars);
4581    SCIPfreeBufferArray(scip, &gubconsGOC1 );
4582    SCIPfreeBufferArray(scip, &gubconsGNC1);
4583 
4584    return SCIP_OKAY;
4585 }
4586 
4587 /** lifts given minimal cover inequality
4588  *  \f[
4589  *    \sum_{j \in C} x_j \leq |C| - 1
4590  *  \f]
4591  *  valid for
4592  *  \f[
4593  *    S^0 = \{ x \in {0,1}^{|C|} : \sum_{j \in C} a_j x_j \leq a_0 \}
4594  *  \f]
4595  *  to a valid inequality
4596  *  \f[
4597  *    \sum_{j \in C} x_j + \sum_{j \in N \setminus C} \alpha_j x_j \leq |C| - 1
4598  *  \f]
4599  *  for
4600  *  \f[
4601  *    S = \{ x \in {0,1}^{|N|} : \sum_{j \in N} a_j x_j \leq a_0 \};
4602  *  \f]
4603  *  uses superadditive up-lifting for the variables in \f$N \setminus C\f$.
4604  */
4605 static
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)4606 SCIP_RETCODE superadditiveUpLifting(
4607    SCIP*                 scip,               /**< SCIP data structure */
4608    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
4609    int                   nvars,              /**< number of variables in knapsack constraint */
4610    int                   ntightened,         /**< number of variables with tightened upper bound */
4611    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
4612    SCIP_Longint          capacity,           /**< capacity of knapsack */
4613    SCIP_Real*            solvals,            /**< solution values of all problem variables */
4614    int*                  covervars,          /**< cover variables */
4615    int*                  noncovervars,       /**< noncover variables */
4616    int                   ncovervars,         /**< number of cover variables */
4617    int                   nnoncovervars,      /**< number of noncover variables */
4618    SCIP_Longint          coverweight,        /**< weight of cover */
4619    SCIP_Real*            liftcoefs,          /**< pointer to store lifting coefficient of vars in knapsack constraint */
4620    SCIP_Real*            cutact              /**< pointer to store activity of lifted valid inequality */
4621    )
4622 {
4623    SCIP_Longint* maxweightsums;
4624    SCIP_Longint* intervalends;
4625    SCIP_Longint* rhos;
4626    SCIP_Real* sortkeys;
4627    SCIP_Longint lambda;
4628    int j;
4629    int h;
4630 
4631    assert(scip != NULL);
4632    assert(vars != NULL);
4633    assert(nvars >= 0);
4634    assert(weights != NULL);
4635    assert(capacity >= 0);
4636    assert(solvals != NULL);
4637    assert(covervars != NULL);
4638    assert(noncovervars != NULL);
4639    assert(ncovervars > 0 && ncovervars <= nvars);
4640    assert(nnoncovervars >= 0 && nnoncovervars <= nvars - ntightened);
4641    assert(ncovervars + nnoncovervars == nvars - ntightened);
4642    assert(liftcoefs != NULL);
4643    assert(cutact != NULL);
4644 
4645    /* allocates temporary memory */
4646    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, ncovervars) );
4647    SCIP_CALL( SCIPallocBufferArray(scip, &maxweightsums, ncovervars + 1) );
4648    SCIP_CALL( SCIPallocBufferArray(scip, &intervalends, ncovervars) );
4649    SCIP_CALL( SCIPallocBufferArray(scip, &rhos, ncovervars) );
4650 
4651    /* initializes data structures */
4652    BMSclearMemoryArray(liftcoefs, nvars);
4653    *cutact = 0.0;
4654 
4655    /* sets lifting coefficient of variables in C, sorts variables in C such that a_1 >= a_2 >= ... >= a_|C|
4656     * and calculates activity of current valid inequality
4657     */
4658    for( j = 0; j < ncovervars; j++ )
4659    {
4660       assert(liftcoefs[covervars[j]] == 0.0);
4661       liftcoefs[covervars[j]] = 1.0;
4662       sortkeys[j] = (SCIP_Real) weights[covervars[j]];
4663       (*cutact) += solvals[covervars[j]];
4664    }
4665    SCIPsortDownRealInt(sortkeys, covervars, ncovervars);
4666 
4667    /* calculates weight excess of cover C */
4668    lambda = coverweight - capacity;
4669    assert(lambda > 0);
4670 
4671    /* calculates A_h for h = 0,...,|C|, I_h for h = 1,...,|C| and rho_h for h = 1,...,|C| */
4672    maxweightsums[0] = 0;
4673    for( h = 1; h <= ncovervars; h++ )
4674    {
4675       maxweightsums[h] = maxweightsums[h-1] + weights[covervars[h-1]];
4676       intervalends[h-1] = maxweightsums[h] - lambda;
4677       rhos[h-1] = MAX(0, weights[covervars[h-1]] - weights[covervars[0]] + lambda);
4678    }
4679 
4680    /* sorts variables in N\C such that a_{j_1} <= a_{j_2} <= ... <= a_{j_t} */
4681    for( j = 0; j < nnoncovervars; j++ )
4682       sortkeys[j] = (SCIP_Real) (weights[noncovervars[j]]);
4683    SCIPsortRealInt(sortkeys, noncovervars, nnoncovervars);
4684 
4685    /* calculates lifting coefficient for all variables in N\C */
4686    h = 0;
4687    for( j = 0; j < nnoncovervars; j++ )
4688    {
4689       int liftvar;
4690       SCIP_Longint weight;
4691       SCIP_Real liftcoef;
4692 
4693       liftvar = noncovervars[j];
4694       weight = weights[liftvar];
4695 
4696       while( intervalends[h] < weight )
4697          h++;
4698 
4699       if( h == 0 )
4700          liftcoef = h;
4701       else
4702       {
4703          if( weight <= intervalends[h-1] + rhos[h] )
4704          {
4705             SCIP_Real tmp1;
4706             SCIP_Real tmp2;
4707             tmp1 =  (SCIP_Real) (intervalends[h-1] + rhos[h] - weight);
4708             tmp2 =  (SCIP_Real) rhos[1];
4709             liftcoef = h - ( tmp1 / tmp2 );
4710          }
4711          else
4712             liftcoef = h;
4713       }
4714 
4715       /* sets lifting coefficient */
4716       assert(liftcoefs[liftvar] == 0.0);
4717       liftcoefs[liftvar] = liftcoef;
4718 
4719       /* updates activity of current valid inequality */
4720       (*cutact) += liftcoef * solvals[liftvar];
4721    }
4722 
4723    /* frees temporary memory */
4724    SCIPfreeBufferArray(scip, &rhos);
4725    SCIPfreeBufferArray(scip, &intervalends);
4726    SCIPfreeBufferArray(scip, &maxweightsums);
4727    SCIPfreeBufferArray(scip, &sortkeys);
4728 
4729    return SCIP_OKAY;
4730 }
4731 
4732 
4733 /** separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information, if wanted, for
4734  *  given knapsack problem
4735 */
4736 static
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)4737 SCIP_RETCODE separateSequLiftedMinimalCoverInequality(
4738    SCIP*                 scip,               /**< SCIP data structure */
4739    SCIP_CONS*            cons,               /**< originating constraint of the knapsack problem, or NULL */
4740    SCIP_SEPA*            sepa,               /**< originating separator of the knapsack problem, or NULL */
4741    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
4742    int                   nvars,              /**< number of variables in knapsack constraint */
4743    int                   ntightened,         /**< number of variables with tightened upper bound */
4744    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
4745    SCIP_Longint          capacity,           /**< capacity of knapsack */
4746    SCIP_Real*            solvals,            /**< solution values of all problem variables */
4747    int*                  mincovervars,       /**< mincover variables */
4748    int*                  nonmincovervars,    /**< nonmincover variables */
4749    int                   nmincovervars,      /**< number of mincover variables */
4750    int                   nnonmincovervars,   /**< number of nonmincover variables */
4751    SCIP_SOL*             sol,                /**< primal SCIP solution to separate, NULL for current LP solution */
4752    SCIP_GUBSET*          gubset,             /**< GUB set data structure, NULL if no GUB information should be used */
4753    SCIP_Bool*            cutoff,             /**< pointer to store whether a cutoff has been detected */
4754    int*                  ncuts               /**< pointer to add up the number of found cuts */
4755    )
4756 {
4757    int* varsC1;
4758    int* varsC2;
4759    int* varsF;
4760    int* varsR;
4761    int nvarsC1;
4762    int nvarsC2;
4763    int nvarsF;
4764    int nvarsR;
4765    SCIP_Real cutact;
4766    int* liftcoefs;
4767    int liftrhs;
4768 
4769    assert( cutoff != NULL );
4770    *cutoff = FALSE;
4771 
4772    /* allocates temporary memory */
4773    SCIP_CALL( SCIPallocBufferArray(scip, &varsC1, nvars) );
4774    SCIP_CALL( SCIPallocBufferArray(scip, &varsC2, nvars) );
4775    SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
4776    SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
4777    SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
4778 
4779    /* 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
4780     * as follows
4781     *   C_2 = { j in C : x*_j = 1 } and
4782     *   C_1 = C\C_2
4783     */
4784    getPartitionCovervars(scip, solvals, mincovervars, nmincovervars, varsC1, varsC2, &nvarsC1, &nvarsC2);
4785    assert(nvarsC1 + nvarsC2 == nmincovervars);
4786    assert(nmincovervars > 0);
4787    assert(nvarsC1 >= 0); /* nvarsC1 > 0 does not always hold, because relaxed knapsack conss may already be violated */
4788 
4789    /* changes partition (C_1,C_2) of minimal cover C, if |C1| = 1, by moving one variable from C2 to C1 */
4790    if( nvarsC1 < 2 && nvarsC2 > 0)
4791    {
4792       SCIP_CALL( changePartitionCovervars(scip, weights, varsC1, varsC2, &nvarsC1, &nvarsC2) );
4793       assert(nvarsC1 >= 1);
4794    }
4795    assert(nvarsC2 == 0 || nvarsC1 >= 1);
4796 
4797    /* gets partition (F,R) of N\C, i.e. F & R = N\C and F cap R = emptyset; chooses partition as follows
4798     *   R = { j in N\C : x*_j = 0 } and
4799     *   F = (N\C)\F
4800     */
4801    getPartitionNoncovervars(scip, solvals, nonmincovervars, nnonmincovervars, varsF, varsR, &nvarsF, &nvarsR);
4802    assert(nvarsF + nvarsR == nnonmincovervars);
4803    assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4804 
4805    /* lift cuts without GUB information */
4806    if( gubset == NULL )
4807    {
4808       /* sorts variables in F, C_2, R according to the second level lifting sequence that will be used in the sequential
4809        * lifting procedure
4810        */
4811       SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsC2, varsR, nvarsF, nvarsC2, nvarsR) );
4812 
4813       /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4814        *
4815        *    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 }
4816        *
4817        * 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
4818        *
4819        *      S = { x in {0,1}^|N|   : sum_{j in N}   a_j x_j <= a_0 },
4820        *
4821        * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in C_2 and sequential
4822        * up-lifting for the variables in R according to the second level lifting sequence
4823        */
4824       SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsC1, varsC2,
4825             varsF, varsR, nvarsC1, nvarsC2, nvarsF, nvarsR, nvarsC1 - 1, liftcoefs, &cutact, &liftrhs) );
4826    }
4827    /* lift cuts with GUB information */
4828    else
4829    {
4830       int* gubconsGC1;
4831       int* gubconsGC2;
4832       int* gubconsGFC1;
4833       int* gubconsGR;
4834       int ngubconsGC1;
4835       int ngubconsGC2;
4836       int ngubconsGFC1;
4837       int ngubconsGR;
4838       int ngubconss;
4839       int nconstightened;
4840       int maxgubvarssize;
4841 
4842       assert(nvars == gubset->nvars);
4843 
4844       ngubconsGC1 = 0;
4845       ngubconsGC2 = 0;
4846       ngubconsGFC1 = 0;
4847       ngubconsGR = 0;
4848       ngubconss = gubset->ngubconss;
4849       nconstightened = 0;
4850       maxgubvarssize = 0;
4851 
4852       /* allocates temporary memory */
4853       SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC1, ngubconss) );
4854       SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGC2, ngubconss) );
4855       SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGFC1, ngubconss) );
4856       SCIP_CALL( SCIPallocBufferArray(scip, &gubconsGR, ngubconss) );
4857 
4858       /* categorizies GUBs of knapsack GUB partion into GOC1, GNC1, GF, GC2, and GR and computes a lifting sequence of
4859        * the GUBs for the sequential GUB wise lifting procedure
4860        */
4861       SCIP_CALL( getLiftingSequenceGUB(scip, gubset, solvals, weights, varsC1, varsC2, varsF, varsR, nvarsC1,
4862             nvarsC2, nvarsF, nvarsR, gubconsGC1, gubconsGC2, gubconsGFC1, gubconsGR, &ngubconsGC1, &ngubconsGC2,
4863             &ngubconsGFC1, &ngubconsGR, &nconstightened, &maxgubvarssize) );
4864 
4865       /* lifts minimal cover inequality sum_{j in C_1} x_j <= |C_1| - 1 valid for
4866        *
4867        *    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,
4868        *                               sum_{j in Q_i} x_j <= 1, forall i in I }
4869        *
4870        * 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
4871        *
4872        *      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 },
4873        *
4874        *  uses sequential up-lifting   for the variables in GUB constraints in gubconsGFC1,
4875        *       sequential down-lifting for the variables in GUB constraints in gubconsGC2, and
4876        *       sequential up-lifting   for the variabels in GUB constraints in gubconsGR.
4877        */
4878       SCIP_CALL( sequentialUpAndDownLiftingGUB(scip, gubset, vars, nconstightened, weights, capacity, solvals, gubconsGC1,
4879             gubconsGC2, gubconsGFC1, gubconsGR, ngubconsGC1, ngubconsGC2, ngubconsGFC1, ngubconsGR,
4880             MIN(nvarsC1 - 1, ngubconsGC1), liftcoefs, &cutact, &liftrhs, maxgubvarssize) );
4881 
4882       /* frees temporary memory */
4883       SCIPfreeBufferArray(scip, &gubconsGR);
4884       SCIPfreeBufferArray(scip, &gubconsGFC1);
4885       SCIPfreeBufferArray(scip, &gubconsGC2);
4886       SCIPfreeBufferArray(scip, &gubconsGC1);
4887    }
4888 
4889    /* checks, if lifting yielded a violated cut */
4890    if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
4891    {
4892       SCIP_ROW* row;
4893       char name[SCIP_MAXSTRLEN];
4894       int j;
4895 
4896       /* creates LP row */
4897       assert( cons == NULL || sepa == NULL );
4898       if ( cons != NULL )
4899       {
4900          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
4901          SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
4902             cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
4903             cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
4904       }
4905       else if ( sepa != NULL )
4906       {
4907          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
4908          SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4909       }
4910       else
4911       {
4912          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcseq_%d", *ncuts);
4913          SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
4914       }
4915 
4916       /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
4917       SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
4918       assert(nvarsC1 + nvarsC2 + nvarsF + nvarsR == nvars - ntightened);
4919       for( j = 0; j < nvarsC1; j++ )
4920       {
4921          SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC1[j]], 1.0) );
4922       }
4923       for( j = 0; j < nvarsC2; j++ )
4924       {
4925          if( liftcoefs[varsC2[j]] > 0 )
4926          {
4927             SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsC2[j]], (SCIP_Real)liftcoefs[varsC2[j]]) );
4928          }
4929       }
4930       for( j = 0; j < nvarsF; j++ )
4931       {
4932          if( liftcoefs[varsF[j]] > 0 )
4933          {
4934             SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
4935          }
4936       }
4937       for( j = 0; j < nvarsR; j++ )
4938       {
4939          if( liftcoefs[varsR[j]] > 0 )
4940          {
4941             SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
4942          }
4943       }
4944       SCIP_CALL( SCIPflushRowExtensions(scip, row) );
4945 
4946       /* checks, if cut is violated enough */
4947       if( SCIPisCutEfficacious(scip, sol, row) )
4948       {
4949          if( cons != NULL )
4950          {
4951             SCIP_CALL( SCIPresetConsAge(scip, cons) );
4952          }
4953          SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
4954          (*ncuts)++;
4955       }
4956       SCIP_CALL( SCIPreleaseRow(scip, &row) );
4957    }
4958 
4959    /* frees temporary memory */
4960    SCIPfreeBufferArray(scip, &liftcoefs);
4961    SCIPfreeBufferArray(scip, &varsR);
4962    SCIPfreeBufferArray(scip, &varsF);
4963    SCIPfreeBufferArray(scip, &varsC2);
4964    SCIPfreeBufferArray(scip, &varsC1);
4965 
4966    return SCIP_OKAY;
4967 }
4968 
4969 /** separates lifted extended weight inequalities using sequential up- and down-lifting for given knapsack problem */
4970 static
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)4971 SCIP_RETCODE separateSequLiftedExtendedWeightInequality(
4972    SCIP*                 scip,               /**< SCIP data structure */
4973    SCIP_CONS*            cons,               /**< constraint that originates the knapsack problem, or NULL */
4974    SCIP_SEPA*            sepa,               /**< originating separator of the knapsack problem, or NULL */
4975    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
4976    int                   nvars,              /**< number of variables in knapsack constraint */
4977    int                   ntightened,         /**< number of variables with tightened upper bound */
4978    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
4979    SCIP_Longint          capacity,           /**< capacity of knapsack */
4980    SCIP_Real*            solvals,            /**< solution values of all problem variables */
4981    int*                  feassetvars,        /**< variables in feasible set */
4982    int*                  nonfeassetvars,     /**< variables not in feasible set */
4983    int                   nfeassetvars,       /**< number of variables in feasible set */
4984    int                   nnonfeassetvars,    /**< number of variables not in feasible set */
4985    SCIP_SOL*             sol,                /**< primal SCIP solution to separate, NULL for current LP solution */
4986    SCIP_Bool*            cutoff,             /**< whether a cutoff has been detected */
4987    int*                  ncuts               /**< pointer to add up the number of found cuts */
4988    )
4989 {
4990    int* varsT1;
4991    int* varsT2;
4992    int* varsF;
4993    int* varsR;
4994    int* liftcoefs;
4995    SCIP_Real cutact;
4996    int nvarsT1;
4997    int nvarsT2;
4998    int nvarsF;
4999    int nvarsR;
5000    int liftrhs;
5001    int j;
5002 
5003    assert( cutoff != NULL );
5004    *cutoff = FALSE;
5005 
5006    /* allocates temporary memory */
5007    SCIP_CALL( SCIPallocBufferArray(scip, &varsT1, nvars) );
5008    SCIP_CALL( SCIPallocBufferArray(scip, &varsT2, nvars) );
5009    SCIP_CALL( SCIPallocBufferArray(scip, &varsF, nvars) );
5010    SCIP_CALL( SCIPallocBufferArray(scip, &varsR, nvars) );
5011    SCIP_CALL( SCIPallocBufferArray(scip, &liftcoefs, nvars) );
5012 
5013    /* 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
5014     * as follows
5015     *   T_2 = { j in T : x*_j = 1 } and
5016     *   T_1 = T\T_2
5017     */
5018    getPartitionCovervars(scip, solvals, feassetvars, nfeassetvars, varsT1, varsT2, &nvarsT1, &nvarsT2);
5019    assert(nvarsT1 + nvarsT2 == nfeassetvars);
5020 
5021    /* changes partition (T_1,T_2) of feasible set T, if |T1| = 0, by moving one variable from T2 to T1 */
5022    if( nvarsT1 == 0 && nvarsT2 > 0)
5023    {
5024       SCIP_CALL( changePartitionFeasiblesetvars(scip, weights, varsT1, varsT2, &nvarsT1, &nvarsT2) );
5025       assert(nvarsT1 == 1);
5026    }
5027    assert(nvarsT2 == 0 || nvarsT1 > 0);
5028 
5029    /* gets partition (F,R) of N\T, i.e. F & R = N\T and F cap R = emptyset; chooses partition as follows
5030     *   R = { j in N\T : x*_j = 0 } and
5031     *   F = (N\T)\F
5032     */
5033    getPartitionNoncovervars(scip, solvals, nonfeassetvars, nnonfeassetvars, varsF, varsR, &nvarsF, &nvarsR);
5034    assert(nvarsF + nvarsR == nnonfeassetvars);
5035    assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5036 
5037    /* sorts variables in F, T_2, and R according to the second level lifting sequence that will be used in the sequential
5038     * lifting procedure (the variable removed last from the initial cover does not have to be lifted first, therefore it
5039     * is included in the sorting routine)
5040     */
5041    SCIP_CALL( getLiftingSequence(scip, solvals, weights, varsF, varsT2, varsR, nvarsF, nvarsT2, nvarsR) );
5042 
5043    /* lifts extended weight inequality sum_{j in T_1} x_j <= |T_1| valid for
5044     *
5045     *    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 }
5046     *
5047     * 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
5048     *
5049     *      S = { x in {0,1}^|N|   : sum_{j in N}   a_j x_j <= a_0 },
5050     *
5051     * uses sequential up-lifting for the variables in F, sequential down-lifting for the variable in T_2 and sequential
5052     * up-lifting for the variabels in R according to the second level lifting sequence
5053     */
5054    SCIP_CALL( sequentialUpAndDownLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, varsT1, varsT2, varsF, varsR,
5055          nvarsT1, nvarsT2, nvarsF, nvarsR, nvarsT1, liftcoefs, &cutact, &liftrhs) );
5056 
5057    /* checks, if lifting yielded a violated cut */
5058    if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5059    {
5060       SCIP_ROW* row;
5061       char name[SCIP_MAXSTRLEN];
5062 
5063       /* creates LP row */
5064       assert( cons == NULL || sepa == NULL );
5065       if( cons != NULL )
5066       {
5067          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5068          SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5069                cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5070                cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5071       }
5072       else if ( sepa != NULL )
5073       {
5074          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_ewseq_%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5075          SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5076       }
5077       else
5078       {
5079          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_ewseq_%d", *ncuts);
5080          SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5081       }
5082 
5083       /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5084       SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5085       assert(nvarsT1 + nvarsT2 + nvarsF + nvarsR == nvars - ntightened);
5086       for( j = 0; j < nvarsT1; j++ )
5087       {
5088          SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT1[j]], 1.0) );
5089       }
5090       for( j = 0; j < nvarsT2; j++ )
5091       {
5092          if( liftcoefs[varsT2[j]] > 0 )
5093          {
5094             SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsT2[j]], (SCIP_Real)liftcoefs[varsT2[j]]) );
5095          }
5096       }
5097       for( j = 0; j < nvarsF; j++ )
5098       {
5099          if( liftcoefs[varsF[j]] > 0 )
5100          {
5101             SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsF[j]], (SCIP_Real)liftcoefs[varsF[j]]) );
5102          }
5103       }
5104       for( j = 0; j < nvarsR; j++ )
5105       {
5106          if( liftcoefs[varsR[j]] > 0 )
5107          {
5108             SCIP_CALL( SCIPaddVarToRow(scip, row, vars[varsR[j]], (SCIP_Real)liftcoefs[varsR[j]]) );
5109          }
5110       }
5111       SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5112 
5113       /* checks, if cut is violated enough */
5114       if( SCIPisCutEfficacious(scip, sol, row) )
5115       {
5116          if( cons != NULL )
5117          {
5118             SCIP_CALL( SCIPresetConsAge(scip, cons) );
5119          }
5120          SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5121          (*ncuts)++;
5122       }
5123       SCIP_CALL( SCIPreleaseRow(scip, &row) );
5124    }
5125 
5126    /* frees temporary memory */
5127    SCIPfreeBufferArray(scip, &liftcoefs);
5128    SCIPfreeBufferArray(scip, &varsR);
5129    SCIPfreeBufferArray(scip, &varsF);
5130    SCIPfreeBufferArray(scip, &varsT2);
5131    SCIPfreeBufferArray(scip, &varsT1);
5132 
5133    return SCIP_OKAY;
5134 }
5135 
5136 /** separates lifted minimal cover inequalities using superadditive up-lifting for given knapsack problem */
5137 static
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)5138 SCIP_RETCODE separateSupLiftedMinimalCoverInequality(
5139    SCIP*                 scip,               /**< SCIP data structure */
5140    SCIP_CONS*            cons,               /**< constraint that originates the knapsack problem, or NULL */
5141    SCIP_SEPA*            sepa,               /**< originating separator of the knapsack problem, or NULL */
5142    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
5143    int                   nvars,              /**< number of variables in knapsack constraint */
5144    int                   ntightened,         /**< number of variables with tightened upper bound */
5145    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
5146    SCIP_Longint          capacity,           /**< capacity of knapsack */
5147    SCIP_Real*            solvals,            /**< solution values of all problem variables */
5148    int*                  mincovervars,       /**< mincover variables */
5149    int*                  nonmincovervars,    /**< nonmincover variables */
5150    int                   nmincovervars,      /**< number of mincover variables */
5151    int                   nnonmincovervars,   /**< number of nonmincover variables */
5152    SCIP_Longint          mincoverweight,     /**< weight of minimal cover */
5153    SCIP_SOL*             sol,                /**< primal SCIP solution to separate, NULL for current LP solution */
5154    SCIP_Bool*            cutoff,             /**< whether a cutoff has been detected */
5155    int*                  ncuts               /**< pointer to add up the number of found cuts */
5156    )
5157 {
5158    SCIP_Real* realliftcoefs;
5159    SCIP_Real cutact;
5160    int liftrhs;
5161 
5162    assert( cutoff != NULL );
5163    *cutoff = FALSE;
5164    cutact = 0.0;
5165 
5166    /* allocates temporary memory */
5167    SCIP_CALL( SCIPallocBufferArray(scip, &realliftcoefs, nvars) );
5168 
5169    /* lifts minimal cover inequality sum_{j in C} x_j <= |C| - 1 valid for
5170     *
5171     *    S^0 = { x in {0,1}^|C| : sum_{j in C} a_j x_j <= a_0 }
5172     *
5173     * to a valid inequality sum_{j in C} x_j + sum_{j in N\C} alpha_j x_j <= |C| - 1 for
5174     *
5175     *      S = { x in {0,1}^|N|   : sum_{j in N}   a_j x_j <= a_0 },
5176     *
5177     * uses superadditive up-lifting for the variables in N\C.
5178     */
5179    SCIP_CALL( superadditiveUpLifting(scip, vars, nvars, ntightened, weights, capacity, solvals, mincovervars,
5180          nonmincovervars, nmincovervars, nnonmincovervars, mincoverweight, realliftcoefs, &cutact) );
5181    liftrhs = nmincovervars - 1;
5182 
5183    /* checks, if lifting yielded a violated cut */
5184    if( SCIPisEfficacious(scip, (cutact - liftrhs)/sqrt((SCIP_Real)MAX(liftrhs, 1))) )
5185    {
5186       SCIP_ROW* row;
5187       char name[SCIP_MAXSTRLEN];
5188       int j;
5189 
5190       /* creates LP row */
5191       assert( cons == NULL || sepa == NULL );
5192       if ( cons != NULL )
5193       {
5194          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPconsGetName(cons), SCIPconshdlrGetNCutsFound(SCIPconsGetHdlr(cons)));
5195          SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)liftrhs,
5196                cons != NULL ? SCIPconsIsLocal(cons) : FALSE, FALSE,
5197                cons != NULL ? SCIPconsIsRemovable(cons) : TRUE) );
5198       }
5199       else if ( sepa != NULL )
5200       {
5201          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_mcsup%" SCIP_LONGINT_FORMAT "", SCIPsepaGetName(sepa), SCIPsepaGetNCutsFound(sepa));
5202          SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &row, sepa, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5203       }
5204       else
5205       {
5206          (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nn_mcsup_%d", *ncuts);
5207          SCIP_CALL( SCIPcreateEmptyRowUnspec(scip, &row, name, -SCIPinfinity(scip), (SCIP_Real)liftrhs, FALSE, FALSE, TRUE) );
5208       }
5209 
5210       /* adds all variables in the knapsack constraint with calculated lifting coefficient to the cut */
5211       SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
5212       assert(nmincovervars + nnonmincovervars == nvars - ntightened);
5213       for( j = 0; j < nmincovervars; j++ )
5214       {
5215          SCIP_CALL( SCIPaddVarToRow(scip, row, vars[mincovervars[j]], 1.0) );
5216       }
5217       for( j = 0; j < nnonmincovervars; j++ )
5218       {
5219          assert(SCIPisFeasGE(scip, realliftcoefs[nonmincovervars[j]], 0.0));
5220          if( SCIPisFeasGT(scip, realliftcoefs[nonmincovervars[j]], 0.0) )
5221          {
5222             SCIP_CALL( SCIPaddVarToRow(scip, row, vars[nonmincovervars[j]], realliftcoefs[nonmincovervars[j]]) );
5223          }
5224       }
5225       SCIP_CALL( SCIPflushRowExtensions(scip, row) );
5226 
5227       /* checks, if cut is violated enough */
5228       if( SCIPisCutEfficacious(scip, sol, row) )
5229       {
5230          if( cons != NULL )
5231          {
5232             SCIP_CALL( SCIPresetConsAge(scip, cons) );
5233          }
5234          SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
5235          (*ncuts)++;
5236       }
5237       SCIP_CALL( SCIPreleaseRow(scip, &row) );
5238    }
5239 
5240    /* frees temporary memory */
5241    SCIPfreeBufferArray(scip, &realliftcoefs);
5242 
5243    return SCIP_OKAY;
5244 }
5245 
5246 /** converts given cover C to a minimal cover by removing variables in the reverse order in which the variables were chosen
5247  *  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
5248  *  C and in the order of non-increasing (1 - x*_j), if the modified transformed separation problem was used to find C;
5249  *  note that all variables with x*_j = 1 will be removed last
5250  */
5251 static
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)5252 SCIP_RETCODE makeCoverMinimal(
5253    SCIP*                 scip,               /**< SCIP data structure */
5254    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
5255    SCIP_Longint          capacity,           /**< capacity of knapsack */
5256    SCIP_Real*            solvals,            /**< solution values of all problem variables */
5257    int*                  covervars,          /**< pointer to store cover variables */
5258    int*                  noncovervars,       /**< pointer to store noncover variables */
5259    int*                  ncovervars,         /**< pointer to store number of cover variables */
5260    int*                  nnoncovervars,      /**< pointer to store number of noncover variables */
5261    SCIP_Longint*         coverweight,        /**< pointer to store weight of cover */
5262    SCIP_Bool             modtransused        /**< TRUE if mod trans sepa prob was used to find cover */
5263    )
5264 {
5265    SORTKEYPAIR** sortkeypairs;
5266    SORTKEYPAIR** sortkeypairssorted;
5267    SCIP_Longint minweight;
5268    int nsortkeypairs;
5269    int minweightidx;
5270    int j;
5271    int k;
5272 
5273    assert(scip != NULL);
5274    assert(covervars != NULL);
5275    assert(noncovervars != NULL);
5276    assert(ncovervars != NULL);
5277    assert(*ncovervars > 0);
5278    assert(nnoncovervars != NULL);
5279    assert(*nnoncovervars >= 0);
5280    assert(coverweight != NULL);
5281    assert(*coverweight > 0);
5282    assert(*coverweight > capacity);
5283 
5284    /* allocates temporary memory; we need two arrays for the keypairs in order to be able to free them in the correct
5285     * order */
5286    nsortkeypairs = *ncovervars;
5287    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairs, nsortkeypairs) );
5288    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeypairssorted, nsortkeypairs) );
5289 
5290    /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5291     *   such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|,  if          trans separation problem was used to find C
5292     *   such that (1 - x*_1)     >= ... >= (1 - x*_|C|),        if modified trans separation problem was used to find C
5293     * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5294     */
5295    assert(*ncovervars == nsortkeypairs);
5296    if( modtransused )
5297    {
5298       for( j = 0; j < *ncovervars; j++ )
5299       {
5300          SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5301          sortkeypairssorted[j] = sortkeypairs[j];
5302 
5303          sortkeypairs[j]->key1 = solvals[covervars[j]];
5304          sortkeypairs[j]->key2 = (SCIP_Real) weights[covervars[j]];
5305       }
5306    }
5307    else
5308    {
5309       for( j = 0; j < *ncovervars; j++ )
5310       {
5311          SCIP_CALL( SCIPallocBuffer(scip, &(sortkeypairs[j])) ); /*lint !e866 */
5312          sortkeypairssorted[j] = sortkeypairs[j];
5313 
5314          sortkeypairs[j]->key1 = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5315          sortkeypairs[j]->key2 = (SCIP_Real) (-weights[covervars[j]]);
5316       }
5317    }
5318    SCIPsortPtrInt((void**)sortkeypairssorted, covervars, compSortkeypairs, *ncovervars);
5319 
5320    /* gets j' with a_j' = min{ a_j : j in C } */
5321    minweightidx = 0;
5322    minweight = weights[covervars[minweightidx]];
5323    for( j = 1; j < *ncovervars; j++ )
5324    {
5325       if( weights[covervars[j]] <= minweight )
5326       {
5327          minweightidx = j;
5328          minweight = weights[covervars[minweightidx]];
5329       }
5330    }
5331    assert(minweightidx >= 0 && minweightidx < *ncovervars);
5332    assert(minweight > 0 && minweight <= *coverweight);
5333 
5334    j = 0;
5335    /* removes variables from C until the remaining variables form a minimal cover */
5336    while( j < *ncovervars && ((*coverweight) - minweight > capacity) )
5337    {
5338       assert(minweightidx >= j);
5339       assert(checkMinweightidx(weights, capacity, covervars, *ncovervars, *coverweight, minweightidx, j));
5340 
5341       /* if sum_{i in C} a_i - a_j <= a_0, j cannot be removed from C */
5342       if( (*coverweight) - weights[covervars[j]] <= capacity )
5343       {
5344 	 ++j;
5345          continue;
5346       }
5347 
5348       /* adds j to N\C */
5349       noncovervars[*nnoncovervars] = covervars[j];
5350       (*nnoncovervars)++;
5351 
5352       /* removes j from C */
5353       (*coverweight) -= weights[covervars[j]];
5354       for( k = j; k < (*ncovervars) - 1; k++ )
5355          covervars[k] = covervars[k+1];
5356       (*ncovervars)--;
5357 
5358       /* updates j' with a_j' = min{ a_j : j in C } */
5359       if( j == minweightidx )
5360       {
5361          minweightidx = 0;
5362          minweight = weights[covervars[minweightidx]];
5363          for( k = 1; k < *ncovervars; k++ )
5364          {
5365             if( weights[covervars[k]] <= minweight )
5366             {
5367                minweightidx = k;
5368                minweight = weights[covervars[minweightidx]];
5369             }
5370          }
5371          assert(minweight > 0 && minweight <= *coverweight);
5372          assert(minweightidx >= 0 && minweightidx < *ncovervars);
5373       }
5374       else
5375       {
5376          assert(minweightidx > j);
5377          minweightidx--;
5378       }
5379       /* j needs to stay the same */
5380    }
5381    assert((*coverweight) > capacity);
5382    assert((*coverweight) - minweight <= capacity);
5383 
5384    /* frees temporary memory */
5385    for( j = nsortkeypairs-1; j >= 0; j-- )
5386       SCIPfreeBuffer(scip, &(sortkeypairs[j])); /*lint !e866 */
5387    SCIPfreeBufferArray(scip, &sortkeypairssorted);
5388    SCIPfreeBufferArray(scip, &sortkeypairs);
5389 
5390    return SCIP_OKAY;
5391 }
5392 
5393 /** converts given initial cover C_init to a feasible set by removing variables in the reverse order in which
5394  *  they were chosen to be in C_init:
5395  *   non-increasing (1 - x*_j)/a_j,   if          transformed separation problem was used to find C_init
5396  *   non-increasing (1 - x*_j),       if modified transformed separation problem was used to find C_init.
5397  *  separates lifted extended weight inequalities using sequential up- and down-lifting for this feasible set
5398  *  and all subsequent feasible sets.
5399  */
5400 static
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)5401 SCIP_RETCODE getFeasibleSet(
5402    SCIP*                 scip,               /**< SCIP data structure */
5403    SCIP_CONS*            cons,               /**< constraint that originates the knapsack problem */
5404    SCIP_SEPA*            sepa,               /**< originating separator of the knapsack problem, or NULL */
5405    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
5406    int                   nvars,              /**< number of variables in knapsack constraint */
5407    int                   ntightened,         /**< number of variables with tightened upper bound */
5408    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
5409    SCIP_Longint          capacity,           /**< capacity of knapsack */
5410    SCIP_Real*            solvals,            /**< solution values of all problem variables */
5411    int*                  covervars,          /**< pointer to store cover variables */
5412    int*                  noncovervars,       /**< pointer to store noncover variables */
5413    int*                  ncovervars,         /**< pointer to store number of cover variables */
5414    int*                  nnoncovervars,      /**< pointer to store number of noncover variables */
5415    SCIP_Longint*         coverweight,        /**< pointer to store weight of cover */
5416    SCIP_Bool             modtransused,       /**< TRUE if mod trans sepa prob was used to find cover */
5417    SCIP_SOL*             sol,                /**< primal SCIP solution to separate, NULL for current LP solution */
5418    SCIP_Bool*            cutoff,             /**< whether a cutoff has been detected */
5419    int*                  ncuts               /**< pointer to add up the number of found cuts */
5420    )
5421 {
5422    SCIP_Real* sortkeys;
5423    int j;
5424    int k;
5425 
5426    assert(scip != NULL);
5427    assert(covervars != NULL);
5428    assert(noncovervars != NULL);
5429    assert(ncovervars != NULL);
5430    assert(*ncovervars > 0);
5431    assert(nnoncovervars != NULL);
5432    assert(*nnoncovervars >= 0);
5433    assert(coverweight != NULL);
5434    assert(*coverweight > 0);
5435    assert(*coverweight > capacity);
5436    assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5437    assert(cutoff != NULL);
5438 
5439    *cutoff = FALSE;
5440 
5441    /* allocates temporary memory */
5442    SCIP_CALL( SCIPallocBufferArray(scip, &sortkeys, *ncovervars) );
5443 
5444    /* sorts C in the reverse order in which the variables were chosen to be in the cover, i.e.
5445     *   such that (1 - x*_1)/a_1 >= ... >= (1 - x*_|C|)/a_|C|,  if          trans separation problem was used to find C
5446     *   such that (1 - x*_1)     >= ... >= (1 - x*_|C|),        if modified trans separation problem was used to find C
5447     * note that all variables with x*_j = 1 are in the end of the sorted C, so they will be removed last from C
5448     */
5449    if( modtransused )
5450    {
5451       for( j = 0; j < *ncovervars; j++ )
5452       {
5453          sortkeys[j] = solvals[covervars[j]];
5454          assert(SCIPisFeasGE(scip, sortkeys[j], 0.0));
5455       }
5456    }
5457    else
5458    {
5459       for( j = 0; j < *ncovervars; j++ )
5460       {
5461          sortkeys[j] = (solvals[covervars[j]] - 1.0) / ((SCIP_Real) weights[covervars[j]]);
5462          assert(SCIPisFeasLE(scip, sortkeys[j], 0.0));
5463       }
5464    }
5465    SCIPsortRealInt(sortkeys, covervars, *ncovervars);
5466 
5467    /* removes variables from C_init and separates lifted extended weight inequalities using sequential up- and down-lifting;
5468     * in addition to an extended weight inequality this gives cardinality inequalities */
5469    while( *ncovervars >= 2 )
5470    {
5471       /* adds first element of C_init to N\C_init */
5472       noncovervars[*nnoncovervars] = covervars[0];
5473       (*nnoncovervars)++;
5474 
5475       /* removes first element from C_init */
5476       (*coverweight) -= weights[covervars[0]];
5477       for( k = 0; k < (*ncovervars) - 1; k++ )
5478          covervars[k] = covervars[k+1];
5479       (*ncovervars)--;
5480 
5481       assert(*ncovervars + *nnoncovervars == nvars - ntightened);
5482       if( (*coverweight) <= capacity )
5483       {
5484          SCIP_CALL( separateSequLiftedExtendedWeightInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals,
5485                covervars, noncovervars, *ncovervars, *nnoncovervars, sol, cutoff, ncuts) );
5486       }
5487 
5488       /* stop if cover is too large */
5489       if ( *ncovervars >= MAXCOVERSIZEITERLEWI )
5490          break;
5491    }
5492 
5493    /* frees temporary memory */
5494    SCIPfreeBufferArray(scip, &sortkeys);
5495 
5496    return SCIP_OKAY;
5497 }
5498 
5499 /** separates different classes of valid inequalities for the 0-1 knapsack problem */
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)5500 SCIP_RETCODE SCIPseparateKnapsackCuts(
5501    SCIP*                 scip,               /**< SCIP data structure */
5502    SCIP_CONS*            cons,               /**< originating constraint of the knapsack problem, or NULL */
5503    SCIP_SEPA*            sepa,               /**< originating separator of the knapsack problem, or NULL */
5504    SCIP_VAR**            vars,               /**< variables in knapsack constraint */
5505    int                   nvars,              /**< number of variables in knapsack constraint */
5506    SCIP_Longint*         weights,            /**< weights of variables in knapsack constraint */
5507    SCIP_Longint          capacity,           /**< capacity of knapsack */
5508    SCIP_SOL*             sol,                /**< primal SCIP solution to separate, NULL for current LP solution */
5509    SCIP_Bool             usegubs,            /**< should GUB information be used for separation? */
5510    SCIP_Bool*            cutoff,             /**< pointer to store whether a cutoff has been detected */
5511    int*                  ncuts               /**< pointer to add up the number of found cuts */
5512    )
5513 {
5514    SCIP_Real* solvals;
5515    int* covervars;
5516    int* noncovervars;
5517    SCIP_Bool coverfound;
5518    SCIP_Bool fractional;
5519    SCIP_Bool modtransused;
5520    SCIP_Longint coverweight;
5521    int ncovervars;
5522    int nnoncovervars;
5523    int ntightened;
5524 
5525    assert(scip != NULL);
5526    assert(capacity >= 0);
5527    assert(cutoff != NULL);
5528    assert(ncuts != NULL);
5529 
5530    *cutoff = FALSE;
5531 
5532    if( nvars == 0 )
5533       return SCIP_OKAY;
5534 
5535    assert(vars != NULL);
5536    assert(nvars > 0);
5537    assert(weights != NULL);
5538 
5539    /* increase age of constraint (age is reset to zero, if a cut was found) */
5540    if( cons != NULL )
5541    {
5542       SCIP_CALL( SCIPincConsAge(scip, cons) );
5543    }
5544 
5545    /* allocates temporary memory */
5546    SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
5547    SCIP_CALL( SCIPallocBufferArray(scip, &covervars, nvars) );
5548    SCIP_CALL( SCIPallocBufferArray(scip, &noncovervars, nvars) );
5549 
5550    /* gets solution values of all problem variables */
5551    SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, solvals) );
5552 
5553 #ifdef SCIP_DEBUG
5554    {
5555       int i;
5556 
5557       SCIPdebugMsg(scip, "separate cuts for knapsack constraint originated by cons <%s>:\n",
5558          cons == NULL ? "-" : SCIPconsGetName(cons));
5559       for( i = 0; i < nvars; ++i )
5560       {
5561          SCIPdebugMsgPrint(scip, "%+" SCIP_LONGINT_FORMAT "<%s>(%g)", weights[i], SCIPvarGetName(vars[i]), solvals[i]);
5562       }
5563       SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT "\n", capacity);
5564    }
5565 #endif
5566 
5567    /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting) using GUB information
5568     */
5569    if( usegubs )
5570    {
5571       SCIP_GUBSET* gubset;
5572 
5573       SCIPdebugMsg(scip, "separate LMCI1-GUB cuts:\n");
5574 
5575       /* initializes partion of knapsack variables into nonoverlapping GUB constraints */
5576       SCIP_CALL( GUBsetCreate(scip, &gubset, nvars, weights, capacity) );
5577 
5578       /* constructs sophisticated partition of knapsack variables into nonoverlapping GUBs */
5579       SCIP_CALL( GUBsetGetCliquePartition(scip, gubset, vars, solvals) );
5580       assert(gubset->ngubconss <= nvars);
5581 
5582       /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5583        * MODIFIED transformed separation problem and taking into account the following fixing:
5584        *   j in C_init,           if j in N_1 = {j in N : x*_j = 1} and
5585        *   j in N\C_init,         if j in N_0 = {j in N : x*_j = 0},
5586        * if one exists
5587        */
5588       modtransused = TRUE;
5589       SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5590             &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5591 
5592       assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5593 
5594       /* if x* is not fractional we stop the separation routine */
5595       if( !fractional )
5596       {
5597          SCIPdebugMsg(scip, "   LMCI1-GUB terminated by no variable with fractional LP value.\n");
5598 
5599          /* frees memory for GUB set data structure */
5600          GUBsetFree(scip, &gubset);
5601 
5602          goto TERMINATE;
5603       }
5604 
5605       /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5606       if( coverfound )
5607       {
5608          /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5609           * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5610           */
5611          SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5612                &nnoncovervars, &coverweight, modtransused) );
5613 
5614          /* only separate with GUB information if we have at least one nontrivial GUB (with more than one variable) */
5615          if( gubset->ngubconss < nvars )
5616          {
5617             /* separates lifted minimal cover inequalities using sequential up- and down-lifting and GUB information */
5618             SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5619                   solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, gubset, cutoff, ncuts) );
5620          }
5621          else
5622          {
5623             /* separates lifted minimal cover inequalities using sequential up- and down-lifting, but do not use trivial
5624              * GUB information
5625              */
5626             SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5627                   solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5628          }
5629       }
5630 
5631       /* frees memory for GUB set data structure */
5632       GUBsetFree(scip, &gubset);
5633    }
5634    else
5635    {
5636       /* LMCI1 (lifted minimal cover inequalities using sequential up- and down-lifting)
5637        * (and LMCI2 (lifted minimal cover inequalities using superadditive up-lifting))
5638        */
5639 
5640       /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5641        * MODIFIED transformed separation problem and taking into account the following fixing:
5642        *   j in C_init,           if j in N_1 = {j in N : x*_j = 1} and
5643        *   j in N\C_init,         if j in N_0 = {j in N : x*_j = 0},
5644        * if one exists
5645        */
5646       SCIPdebugMsg(scip, "separate LMCI1 cuts:\n");
5647       modtransused = TRUE;
5648       SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5649             &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5650       assert(!coverfound || !fractional || ncovervars + nnoncovervars == nvars - ntightened);
5651 
5652       /* if x* is not fractional we stop the separation routine */
5653       if( !fractional )
5654          goto TERMINATE;
5655 
5656       /* if no cover was found we stop the separation routine for lifted minimal cover inequality */
5657       if( coverfound )
5658       {
5659          /* converts initial cover C_init to a minimal cover C by removing variables in the reverse order in which the
5660           * variables were chosen to be in C_init; note that variables with x*_j = 1 will be removed last
5661           */
5662          SCIP_CALL( makeCoverMinimal(scip, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5663                &nnoncovervars, &coverweight, modtransused) );
5664 
5665          /* separates lifted minimal cover inequalities using sequential up- and down-lifting */
5666          SCIP_CALL( separateSequLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5667                solvals, covervars, noncovervars, ncovervars, nnoncovervars, sol, NULL, cutoff, ncuts) );
5668 
5669          if( USESUPADDLIFT ) /*lint !e506 !e774*/
5670          {
5671             SCIPdebugMsg(scip, "separate LMCI2 cuts:\n");
5672             /* separates lifted minimal cover inequalities using superadditive up-lifting */
5673             SCIP_CALL( separateSupLiftedMinimalCoverInequality(scip, cons, sepa, vars, nvars, ntightened, weights, capacity,
5674                   solvals, covervars, noncovervars, ncovervars, nnoncovervars, coverweight, sol, cutoff, ncuts) );
5675          }
5676       }
5677    }
5678 
5679    /* LEWI (lifted extended weight inequalities using sequential up- and down-lifting) */
5680    if ( ! (*cutoff) )
5681    {
5682       /* gets a most violated initial cover C_init ( sum_{j in C_init} a_j > a_0 ) by using the
5683        * transformed separation problem and taking into account the following fixing:
5684        *   j in C_init,           if j in N_1 = {j in N : x*_j = 1} and
5685        *   j in N\C_init,         if j in N_0 = {j in N : x*_j = 0},
5686        * if one exists
5687        */
5688       SCIPdebugMsg(scip, "separate LEWI cuts:\n");
5689       modtransused = FALSE;
5690       SCIP_CALL( getCover(scip, vars, nvars, weights, capacity, solvals, covervars, noncovervars, &ncovervars,
5691             &nnoncovervars, &coverweight, &coverfound, modtransused, &ntightened, &fractional) );
5692       assert(fractional);
5693       assert(!coverfound || ncovervars + nnoncovervars == nvars - ntightened);
5694 
5695       /* if no cover was found we stop the separation routine */
5696       if( coverfound )
5697       {
5698          /* converts initial cover C_init to a feasible set by removing variables in the reverse order in which
5699           * they were chosen to be in C_init and separates lifted extended weight inequalities using sequential
5700           * up- and down-lifting for this feasible set and all subsequent feasible sets.
5701           */
5702          SCIP_CALL( getFeasibleSet(scip, cons, sepa, vars, nvars, ntightened, weights, capacity, solvals, covervars, noncovervars,
5703                &ncovervars, &nnoncovervars, &coverweight, modtransused, sol, cutoff, ncuts) );
5704       }
5705    }
5706 
5707  TERMINATE:
5708    /* frees temporary memory */
5709    SCIPfreeBufferArray(scip, &noncovervars);
5710    SCIPfreeBufferArray(scip, &covervars);
5711    SCIPfreeBufferArray(scip, &solvals);
5712 
5713    return SCIP_OKAY;
5714 }
5715 
5716 /* relaxes given general linear constraint into a knapsack constraint and separates lifted knapsack cover inequalities */
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)5717 SCIP_RETCODE SCIPseparateRelaxedKnapsack(
5718    SCIP*                 scip,               /**< SCIP data structure */
5719    SCIP_CONS*            cons,               /**< originating constraint of the knapsack problem, or NULL */
5720    SCIP_SEPA*            sepa,               /**< originating separator of the knapsack problem, or NULL */
5721    int                   nknapvars,          /**< number of variables in the continuous knapsack constraint */
5722    SCIP_VAR**            knapvars,           /**< variables in the continuous knapsack constraint */
5723    SCIP_Real*            knapvals,           /**< coefficients of the variables in the continuous knapsack constraint */
5724    SCIP_Real             valscale,           /**< -1.0 if lhs of row is used as rhs of c. k. constraint, +1.0 otherwise */
5725    SCIP_Real             rhs,                /**< right hand side of the continuous knapsack constraint */
5726    SCIP_SOL*             sol,                /**< primal CIP solution, NULL for current LP solution */
5727    SCIP_Bool*            cutoff,             /**< pointer to store whether a cutoff was found */
5728    int*                  ncuts               /**< pointer to add up the number of found cuts */
5729    )
5730 {
5731    SCIP_VAR** binvars;
5732    SCIP_VAR** consvars;
5733    SCIP_Real* binvals;
5734    SCIP_Longint* consvals;
5735    SCIP_Longint minact;
5736    SCIP_Longint maxact;
5737    SCIP_Real intscalar;
5738    SCIP_Bool success;
5739    int nbinvars;
5740    int nconsvars;
5741    int i;
5742 
5743    int* tmpindices;
5744    int tmp;
5745    SCIP_CONSHDLR* conshdlr;
5746    SCIP_CONSHDLRDATA* conshdlrdata;
5747    SCIP_Bool noknapsackconshdlr;
5748    SCIP_Bool usegubs;
5749 
5750    assert(nknapvars > 0);
5751    assert(knapvars != NULL);
5752    assert(cutoff != NULL);
5753 
5754    tmpindices = NULL;
5755 
5756    SCIPdebugMsg(scip, "separate linear constraint <%s> relaxed to knapsack\n", cons != NULL ? SCIPconsGetName(cons) : "-");
5757    SCIPdebug( if( cons != NULL ) { SCIPdebugPrintCons(scip, cons, NULL); } );
5758 
5759    binvars = SCIPgetVars(scip);
5760 
5761    /* all variables which are of integral type can be potentially of binary type; this can be checked via the method SCIPvarIsBinary(var) */
5762    nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5763 
5764    *cutoff = FALSE;
5765 
5766    if( nbinvars == 0 )
5767       return SCIP_OKAY;
5768 
5769    /* set up data structures */
5770    SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nbinvars) );
5771    SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nbinvars) );
5772 
5773    /* get conshdlrdata to use cleared memory */
5774    conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5775    if( conshdlr == NULL )
5776    {
5777       noknapsackconshdlr = TRUE;
5778       usegubs = DEFAULT_USEGUBS;
5779 
5780       SCIP_CALL( SCIPallocBufferArray(scip, &binvals, nbinvars) );
5781       BMSclearMemoryArray(binvals, nbinvars);
5782    }
5783    else
5784    {
5785       noknapsackconshdlr = FALSE;
5786       conshdlrdata = SCIPconshdlrGetData(conshdlr);
5787       assert(conshdlrdata != NULL);
5788       usegubs = conshdlrdata->usegubs;
5789 
5790       SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, nknapvars) );
5791 
5792       /* increase array size to avoid an endless loop in the next block; this might happen if continuous variables
5793        * change their types to SCIP_VARTYPE_BINARY during presolving
5794        */
5795       if( conshdlrdata->reals1size == 0 )
5796       {
5797          SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, conshdlrdata->reals1size, 1) );
5798          conshdlrdata->reals1size = 1;
5799          conshdlrdata->reals1[0] = 0.0;
5800       }
5801 
5802       assert(conshdlrdata->reals1size > 0);
5803 
5804       /* next if condition should normally not be true, because it means that presolving has created more binary
5805        * variables than binary + integer variables existed at the constraint initialization method, but for example if you would
5806        * transform all integers into their binary representation then it maybe happens
5807        */
5808       if( conshdlrdata->reals1size < nbinvars )
5809       {
5810          int oldsize = conshdlrdata->reals1size;
5811 
5812          conshdlrdata->reals1size = nbinvars;
5813          SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->reals1, oldsize, conshdlrdata->reals1size) );
5814          BMSclearMemoryArray(&(conshdlrdata->reals1[oldsize]), conshdlrdata->reals1size - oldsize); /*lint !e866 */
5815       }
5816       binvals = conshdlrdata->reals1;
5817 
5818       /* check for cleared array, all entries have to be zero */
5819 #ifndef NDEBUG
5820       for( tmp = nbinvars - 1; tmp >= 0; --tmp )
5821       {
5822          assert(binvals[tmp] == 0);
5823       }
5824 #endif
5825    }
5826 
5827    tmp = 0;
5828 
5829    /* relax continuous knapsack constraint:
5830     * 1. make all variables binary:
5831     *    if x_j is continuous or integer variable substitute:
5832     *      - a_j < 0: x_j = lb  or  x_j = b*z + d with variable lower bound b*z + d with binary variable z
5833     *      - a_j > 0: x_j = ub  or  x_j = b*z + d with variable upper bound b*z + d with binary variable z
5834     * 2. convert coefficients of all variables to positive integers:
5835     *      - scale all coefficients a_j to a~_j integral
5836     *      - substitute  x~_j = 1 - x_j if a~_j < 0
5837     */
5838 
5839    /* replace integer and continuous variables with binary variables */
5840    for( i = 0; i < nknapvars; i++ )
5841    {
5842       SCIP_VAR* var;
5843 
5844       var = knapvars[i];
5845 
5846       if( SCIPvarIsBinary(var) && SCIPvarIsActive(var) )
5847       {
5848          SCIP_Real solval;
5849          assert(0 <= SCIPvarGetProbindex(var) && SCIPvarGetProbindex(var) < nbinvars);
5850 
5851          solval = SCIPgetSolVal(scip, sol, var);
5852 
5853          /* knapsack relaxation assumes solution values between 0.0 and 1.0 for binary variables */
5854          if( SCIPisFeasLT(scip, solval, 0.0 )
5855                || SCIPisFeasGT(scip, solval, 1.0) )
5856          {
5857             SCIPdebugMsg(scip, "Solution value %.15g <%s> outside domain [0.0, 1.0]\n",
5858                   solval, SCIPvarGetName(var));
5859             goto TERMINATE;
5860          }
5861 
5862          binvals[SCIPvarGetProbindex(var)] += valscale * knapvals[i];
5863          if( !noknapsackconshdlr )
5864          {
5865             assert(tmpindices != NULL);
5866 
5867             tmpindices[tmp] = SCIPvarGetProbindex(var);
5868             ++tmp;
5869          }
5870          SCIPdebugMsg(scip, " -> binary variable %+.15g<%s>(%.15g)\n", valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var));
5871       }
5872       else if( valscale * knapvals[i] > 0.0 )
5873       {
5874          SCIP_VAR** zvlb;
5875          SCIP_Real* bvlb;
5876          SCIP_Real* dvlb;
5877          SCIP_Real bestlbsol;
5878          int bestlbtype;
5879          int nvlb;
5880          int j;
5881 
5882          /* a_j > 0: substitution with lb or vlb */
5883          nvlb = SCIPvarGetNVlbs(var);
5884          zvlb = SCIPvarGetVlbVars(var);
5885          bvlb = SCIPvarGetVlbCoefs(var);
5886          dvlb = SCIPvarGetVlbConstants(var);
5887 
5888          /* search for lb or vlb with maximal bound value */
5889          bestlbsol = SCIPvarGetLbGlobal(var);
5890          bestlbtype = -1;
5891          for( j = 0; j < nvlb; j++ )
5892          {
5893             /* use only numerical stable vlb with binary variable z */
5894             if( SCIPvarIsBinary(zvlb[j]) && SCIPvarIsActive(zvlb[j]) && REALABS(bvlb[j]) <= MAXABSVBCOEF )
5895             {
5896                SCIP_Real vlbsol;
5897 
5898                if( (bvlb[j] >= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetLbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) ||
5899                    (bvlb[j] <= 0.0 && SCIPisGT(scip, bvlb[j] * SCIPvarGetUbLocal(zvlb[j]) + dvlb[j], SCIPvarGetUbLocal(var))) )
5900                {
5901                   *cutoff = TRUE;
5902                   SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] >= %g<%s>[%g,%g] + %g implies local cutoff\n",
5903                      SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
5904                      bvlb[j], SCIPvarGetName(zvlb[j]), SCIPvarGetLbLocal(zvlb[j]), SCIPvarGetUbLocal(zvlb[j]), dvlb[j]);
5905                   goto TERMINATE;
5906                }
5907 
5908                assert(0 <= SCIPvarGetProbindex(zvlb[j]) && SCIPvarGetProbindex(zvlb[j]) < nbinvars);
5909                vlbsol = bvlb[j] * SCIPgetSolVal(scip, sol, zvlb[j]) + dvlb[j];
5910                if( SCIPisGE(scip, vlbsol, bestlbsol) )
5911                {
5912                   bestlbsol = vlbsol;
5913                   bestlbtype = j;
5914                }
5915             }
5916          }
5917 
5918          /* if no lb or vlb with binary variable was found, we have to abort */
5919          if( SCIPisInfinity(scip, -bestlbsol) )
5920             goto TERMINATE;
5921 
5922          if( bestlbtype == -1 )
5923          {
5924             rhs -= valscale * knapvals[i] * bestlbsol;
5925             SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with lower bound %.15g (rhs=%.15g)\n",
5926                valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbGlobal(var), rhs);
5927          }
5928          else
5929          {
5930             assert(0 <= SCIPvarGetProbindex(zvlb[bestlbtype]) && SCIPvarGetProbindex(zvlb[bestlbtype]) < nbinvars);
5931             rhs -= valscale * knapvals[i] * dvlb[bestlbtype];
5932             binvals[SCIPvarGetProbindex(zvlb[bestlbtype])] += valscale * knapvals[i] * bvlb[bestlbtype];
5933 
5934             if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvlb[bestlbtype])])) )
5935                goto TERMINATE;
5936 
5937             if( !noknapsackconshdlr )
5938             {
5939                assert(tmpindices != NULL);
5940 
5941                tmpindices[tmp] = SCIPvarGetProbindex(zvlb[bestlbtype]);
5942                ++tmp;
5943             }
5944             SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable lower bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
5945                valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
5946                bvlb[bestlbtype], SCIPvarGetName(zvlb[bestlbtype]),
5947                SCIPgetSolVal(scip, sol, zvlb[bestlbtype]), dvlb[bestlbtype], rhs);
5948          }
5949       }
5950       else
5951       {
5952          SCIP_VAR** zvub;
5953          SCIP_Real* bvub;
5954          SCIP_Real* dvub;
5955          SCIP_Real bestubsol;
5956          int bestubtype;
5957          int nvub;
5958          int j;
5959 
5960          assert(valscale * knapvals[i] < 0.0);
5961 
5962          /* a_j < 0: substitution with ub or vub */
5963          nvub = SCIPvarGetNVubs(var);
5964          zvub = SCIPvarGetVubVars(var);
5965          bvub = SCIPvarGetVubCoefs(var);
5966          dvub = SCIPvarGetVubConstants(var);
5967 
5968          /* search for ub or vub with minimal bound value */
5969          bestubsol = SCIPvarGetUbGlobal(var);
5970          bestubtype = -1;
5971          for( j = 0; j < nvub; j++ )
5972          {
5973             /* use only numerical stable vub with active binary variable z */
5974             if( SCIPvarIsBinary(zvub[j]) && SCIPvarIsActive(zvub[j]) && REALABS(bvub[j]) <= MAXABSVBCOEF )
5975             {
5976                SCIP_Real vubsol;
5977 
5978                if( (bvub[j] >= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetUbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) ||
5979                   (bvub[j] <= 0.0 && SCIPisLT(scip, bvub[j] * SCIPvarGetLbLocal(zvub[j]) + dvub[j], SCIPvarGetLbLocal(var))) )
5980                {
5981                   *cutoff = TRUE;
5982                   SCIPdebugMsg(scip, "variable bound <%s>[%g,%g] <= %g<%s>[%g,%g] + %g implies local cutoff\n",
5983                      SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
5984                      bvub[j], SCIPvarGetName(zvub[j]), SCIPvarGetLbLocal(zvub[j]), SCIPvarGetUbLocal(zvub[j]), dvub[j]);
5985                   goto TERMINATE;
5986                }
5987 
5988                assert(0 <= SCIPvarGetProbindex(zvub[j]) && SCIPvarGetProbindex(zvub[j]) < nbinvars);
5989                vubsol = bvub[j] * SCIPgetSolVal(scip, sol, zvub[j]) + dvub[j];
5990                if( SCIPisLE(scip, vubsol, bestubsol) )
5991                {
5992                   bestubsol = vubsol;
5993                   bestubtype = j;
5994                }
5995             }
5996          }
5997 
5998          /* if no ub or vub with binary variable was found, we have to abort */
5999          if( SCIPisInfinity(scip, bestubsol) )
6000             goto TERMINATE;
6001 
6002          if( bestubtype == -1 )
6003          {
6004             rhs -= valscale * knapvals[i] * bestubsol;
6005             SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with upper bound %.15g (rhs=%.15g)\n",
6006                valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetUbGlobal(var), rhs);
6007          }
6008          else
6009          {
6010             assert(0 <= SCIPvarGetProbindex(zvub[bestubtype]) && SCIPvarGetProbindex(zvub[bestubtype]) < nbinvars);
6011             rhs -= valscale * knapvals[i] * dvub[bestubtype];
6012             binvals[SCIPvarGetProbindex(zvub[bestubtype])] += valscale * knapvals[i] * bvub[bestubtype];
6013 
6014             if( SCIPisInfinity(scip, REALABS(binvals[SCIPvarGetProbindex(zvub[bestubtype])])) )
6015                goto TERMINATE;
6016 
6017             if( !noknapsackconshdlr )
6018             {
6019                assert(tmpindices != NULL);
6020 
6021                tmpindices[tmp] = SCIPvarGetProbindex(zvub[bestubtype]);
6022                ++tmp;
6023             }
6024             SCIPdebugMsg(scip, " -> non-binary variable %+.15g<%s>(%.15g) replaced with variable upper bound %+.15g<%s>(%.15g) %+.15g (rhs=%.15g)\n",
6025                valscale * knapvals[i], SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var),
6026                bvub[bestubtype], SCIPvarGetName(zvub[bestubtype]),
6027                SCIPgetSolVal(scip, sol, zvub[bestubtype]), dvub[bestubtype], rhs);
6028          }
6029       }
6030    }
6031 
6032    /* convert coefficients of all (now binary) variables to positive integers:
6033     *   - make all coefficients integral
6034     *   - make all coefficients positive (substitute negated variable)
6035     */
6036    nconsvars = 0;
6037 
6038    /* calculate scalar which makes all coefficients integral in relative allowed difference in between
6039     * -SCIPepsilon(scip) and KNAPSACKRELAX_MAXDELTA
6040     */
6041    SCIP_CALL( SCIPcalcIntegralScalar(binvals, nbinvars, -SCIPepsilon(scip), KNAPSACKRELAX_MAXDELTA,
6042          KNAPSACKRELAX_MAXDNOM, KNAPSACKRELAX_MAXSCALE, &intscalar, &success) );
6043    SCIPdebugMsg(scip, " -> intscalar = %.15g\n", intscalar);
6044 
6045    /* if coefficients cannot be made integral, we have to use a scalar of 1.0 and only round fractional coefficients down */
6046    if( !success )
6047       intscalar = 1.0;
6048 
6049    /* make all coefficients integral and positive:
6050     *  - scale a~_j = a_j * intscalar
6051     *  - substitute x~_j = 1 - x_j if a~_j < 0
6052     */
6053    rhs = rhs * intscalar;
6054 
6055    SCIPdebugMsg(scip, " -> rhs = %.15g\n", rhs);
6056    minact = 0;
6057    maxact = 0;
6058    for( i = 0; i < nbinvars; i++ )
6059    {
6060       SCIP_VAR* var;
6061       SCIP_Longint val;
6062 
6063       val = (SCIP_Longint)SCIPfloor(scip, binvals[i] * intscalar);
6064       if( val == 0 )
6065          continue;
6066 
6067       if( val > 0 )
6068       {
6069          var = binvars[i];
6070          SCIPdebugMsg(scip, " -> positive scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): not changed (rhs=%.15g)\n",
6071             val, SCIPvarGetName(var), binvals[i], rhs);
6072       }
6073       else
6074       {
6075          assert(val < 0);
6076 
6077          SCIP_CALL( SCIPgetNegatedVar(scip, binvars[i], &var) );
6078          val = -val;  /*lint !e2704*/
6079          rhs += val;
6080          SCIPdebugMsg(scip, " -> negative scaled binary variable %+" SCIP_LONGINT_FORMAT "<%s> (unscaled %.15g): substituted by (1 - <%s>) (rhs=%.15g)\n",
6081             -val, SCIPvarGetName(binvars[i]), binvals[i], SCIPvarGetName(var), rhs);
6082       }
6083 
6084       if( SCIPvarGetLbLocal(var) > 0.5 )
6085          minact += val;
6086       if( SCIPvarGetUbLocal(var) > 0.5 )
6087          maxact += val;
6088       consvals[nconsvars] = val;
6089       consvars[nconsvars] = var;
6090       nconsvars++;
6091    }
6092 
6093    if( nconsvars > 0 )
6094    {
6095       SCIP_Longint capacity;
6096 
6097       assert(consvars != NULL);
6098       assert(consvals != NULL);
6099       capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
6100 
6101 #ifdef SCIP_DEBUG
6102       {
6103          SCIP_Real act;
6104 
6105          SCIPdebugMsg(scip, " -> linear constraint <%s> relaxed to knapsack:", cons != NULL ? SCIPconsGetName(cons) : "-");
6106          act = 0.0;
6107          for( i = 0; i < nconsvars; ++i )
6108          {
6109             SCIPdebugMsgPrint(scip, " %+" SCIP_LONGINT_FORMAT "<%s>(%.15g)", consvals[i], SCIPvarGetName(consvars[i]),
6110                SCIPgetSolVal(scip, sol, consvars[i]));
6111             act += consvals[i] * SCIPgetSolVal(scip, sol, consvars[i]);
6112          }
6113          SCIPdebugMsgPrint(scip, " <= %" SCIP_LONGINT_FORMAT " (%.15g) [act: %.15g, min: %" SCIP_LONGINT_FORMAT " max: %" SCIP_LONGINT_FORMAT "]\n",
6114             capacity, rhs, act, minact, maxact);
6115       }
6116 #endif
6117 
6118       if( minact > capacity )
6119       {
6120          SCIPdebugMsg(scip, "minactivity of knapsack relaxation implies local cutoff\n");
6121          *cutoff = TRUE;
6122          goto TERMINATE;
6123       }
6124 
6125       if( maxact > capacity )
6126       {
6127          /* separate lifted cut from relaxed knapsack constraint */
6128          SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, sepa, consvars, nconsvars, consvals, capacity, sol, usegubs, cutoff, ncuts) );
6129       }
6130    }
6131 
6132  TERMINATE:
6133    /* free data structures */
6134    if( noknapsackconshdlr)
6135    {
6136       SCIPfreeBufferArray(scip, &binvals);
6137    }
6138    else
6139    {
6140       /* clear binvals */
6141       for( --tmp; tmp >= 0; --tmp)
6142       {
6143          assert(tmpindices != NULL);
6144          binvals[tmpindices[tmp]] = 0;
6145       }
6146       SCIPfreeBufferArray(scip, &tmpindices);
6147    }
6148    SCIPfreeBufferArray(scip, &consvals);
6149    SCIPfreeBufferArray(scip, &consvars);
6150 
6151    return SCIP_OKAY;
6152 }
6153 
6154 /** separates given knapsack constraint */
6155 static
separateCons(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol,SCIP_Bool sepacuts,SCIP_Bool usegubs,SCIP_Bool * cutoff,int * ncuts)6156 SCIP_RETCODE separateCons(
6157    SCIP*                 scip,               /**< SCIP data structure */
6158    SCIP_CONS*            cons,               /**< knapsack constraint */
6159    SCIP_SOL*             sol,                /**< primal SCIP solution, NULL for current LP solution */
6160    SCIP_Bool             sepacuts,           /**< should knapsack cuts be separated? */
6161    SCIP_Bool             usegubs,            /**< should GUB information be used for separation? */
6162    SCIP_Bool*            cutoff,             /**< whether a cutoff has been detected */
6163    int*                  ncuts               /**< pointer to add up the number of found cuts */
6164    )
6165 {
6166    SCIP_CONSDATA* consdata;
6167    SCIP_Bool violated;
6168 
6169    assert(ncuts != NULL);
6170    assert(cutoff != NULL);
6171    *cutoff = FALSE;
6172 
6173    consdata = SCIPconsGetData(cons);
6174    assert(consdata != NULL);
6175 
6176    SCIPdebugMsg(scip, "separating knapsack constraint <%s>\n", SCIPconsGetName(cons));
6177 
6178    /* check knapsack constraint itself for feasibility */
6179    SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), FALSE, &violated) );
6180 
6181    if( violated )
6182    {
6183       /* add knapsack constraint as LP row to the LP */
6184       SCIP_CALL( addRelaxation(scip, cons, cutoff) );
6185       (*ncuts)++;
6186    }
6187    else if( sepacuts )
6188    {
6189       SCIP_CALL( SCIPseparateKnapsackCuts(scip, cons, NULL, consdata->vars, consdata->nvars, consdata->weights,
6190             consdata->capacity, sol, usegubs, cutoff, ncuts) );
6191    }
6192 
6193    return SCIP_OKAY;
6194 }
6195 
6196 /** adds coefficient to constraint data */
6197 static
addCoef(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Longint weight)6198 SCIP_RETCODE addCoef(
6199    SCIP*                 scip,               /**< SCIP data structure */
6200    SCIP_CONS*            cons,               /**< knapsack constraint */
6201    SCIP_VAR*             var,                /**< variable to add to knapsack */
6202    SCIP_Longint          weight              /**< weight of variable in knapsack */
6203    )
6204 {
6205    SCIP_CONSDATA* consdata;
6206 
6207    consdata = SCIPconsGetData(cons);
6208    assert(consdata != NULL);
6209    assert(SCIPvarIsBinary(var));
6210    assert(weight > 0);
6211 
6212    /* add the new coefficient to the LP row */
6213    if( consdata->row != NULL )
6214    {
6215       SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, (SCIP_Real)weight) );
6216    }
6217 
6218    /* check for fixed variable */
6219    if( SCIPvarGetLbGlobal(var) > 0.5 )
6220    {
6221       /* variable is fixed to one: reduce capacity */
6222       consdata->capacity -= weight;
6223    }
6224    else if( SCIPvarGetUbGlobal(var) > 0.5 )
6225    {
6226       SCIP_Bool negated;
6227 
6228       /* get binary representative of variable */
6229       SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &var, &negated) );
6230 
6231       /* insert coefficient */
6232       SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1, SCIPconsIsTransformed(cons)) );
6233       consdata->vars[consdata->nvars] = var;
6234       consdata->weights[consdata->nvars] = weight;
6235       consdata->nvars++;
6236 
6237       /* capture variable */
6238       SCIP_CALL( SCIPcaptureVar(scip, var) );
6239 
6240       /* install the rounding locks of variable */
6241       SCIP_CALL( lockRounding(scip, cons, var) );
6242 
6243       /* catch events */
6244       if( SCIPconsIsTransformed(cons) )
6245       {
6246          SCIP_CONSHDLRDATA* conshdlrdata;
6247 
6248          conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6249          assert(conshdlrdata != NULL);
6250          SCIP_CALL( eventdataCreate(scip, &consdata->eventdata[consdata->nvars-1], cons, weight) );
6251          SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTTYPE_KNAPSACK,
6252                conshdlrdata->eventhdlr, consdata->eventdata[consdata->nvars-1],
6253                &consdata->eventdata[consdata->nvars-1]->filterpos) );
6254 
6255          if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
6256             consdata->existmultaggr = TRUE;
6257 
6258          /* mark constraint to be propagated and presolved */
6259          SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6260          consdata->presolvedtiming = 0;
6261          consdata->cliquesadded = FALSE; /* new coefficient might lead to larger cliques */
6262       }
6263 
6264       /* update weight sums */
6265       updateWeightSums(consdata, var, weight);
6266 
6267       consdata->sorted = FALSE;
6268       consdata->cliquepartitioned = FALSE;
6269       consdata->negcliquepartitioned = FALSE;
6270       consdata->merged = FALSE;
6271    }
6272 
6273    return SCIP_OKAY;
6274 }
6275 
6276 /** deletes coefficient at given position from constraint data */
6277 static
delCoefPos(SCIP * scip,SCIP_CONS * cons,int pos)6278 SCIP_RETCODE delCoefPos(
6279    SCIP*                 scip,               /**< SCIP data structure */
6280    SCIP_CONS*            cons,               /**< knapsack constraint */
6281    int                   pos                 /**< position of coefficient to delete */
6282    )
6283 {
6284    SCIP_CONSDATA* consdata;
6285    SCIP_VAR* var;
6286 
6287    consdata = SCIPconsGetData(cons);
6288    assert(consdata != NULL);
6289    assert(0 <= pos && pos < consdata->nvars);
6290 
6291    var = consdata->vars[pos];
6292    assert(var != NULL);
6293    assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
6294 
6295    /* delete the coefficient from the LP row */
6296    if( consdata->row != NULL )
6297    {
6298       SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -(SCIP_Real)consdata->weights[pos]) );
6299    }
6300 
6301    /* remove the rounding locks of variable */
6302    SCIP_CALL( unlockRounding(scip, cons, var) );
6303 
6304    /* drop events and mark constraint to be propagated and presolved */
6305    if( SCIPconsIsTransformed(cons) )
6306    {
6307       SCIP_CONSHDLRDATA* conshdlrdata;
6308 
6309       conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
6310       assert(conshdlrdata != NULL);
6311       SCIP_CALL( SCIPdropVarEvent(scip, var, EVENTTYPE_KNAPSACK,
6312             conshdlrdata->eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
6313       SCIP_CALL( eventdataFree(scip, &consdata->eventdata[pos]) );
6314 
6315       SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
6316       consdata->presolvedtiming = 0;
6317       consdata->sorted = (consdata->sorted && pos == consdata->nvars - 1);
6318    }
6319 
6320    /* decrease weight sums */
6321    updateWeightSums(consdata, var, -consdata->weights[pos]);
6322 
6323    /* move the last variable to the free slot */
6324    consdata->vars[pos] = consdata->vars[consdata->nvars-1];
6325    consdata->weights[pos] = consdata->weights[consdata->nvars-1];
6326    if( consdata->eventdata != NULL )
6327       consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
6328 
6329    /* release variable */
6330    SCIP_CALL( SCIPreleaseVar(scip, &var) );
6331 
6332    /* try to use old clique partitions */
6333    if( consdata->cliquepartitioned )
6334    {
6335       assert(consdata->cliquepartition != NULL);
6336       /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6337        * change the clique number */
6338       if( consdata->cliquepartition[consdata->nvars - 1] != consdata->nvars - 1 )
6339       {
6340          int oldcliqenum;
6341 
6342          oldcliqenum = consdata->cliquepartition[pos];
6343          consdata->cliquepartition[pos] = consdata->cliquepartition[consdata->nvars-1];
6344 
6345          /* the following if and else cases assure that we have increasing clique numbers */
6346          if( consdata->cliquepartition[pos] > pos )
6347             consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6348          else
6349          {
6350             int i;
6351             int cliquenumbefore;
6352 
6353             /* if the old clique number was greater than the new one we have to check that before a bigger clique number
6354              * occurs the same as the old one is still in the cliquepartition */
6355             if( oldcliqenum > consdata->cliquepartition[pos] )
6356             {
6357                for( i = 0; i < consdata->nvars; ++i )
6358                   if( oldcliqenum == consdata->cliquepartition[i] )
6359                      break;
6360                   else if( oldcliqenum < consdata->cliquepartition[i] )
6361                   {
6362                      consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6363                      break;
6364                   }
6365                /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6366                 * the biggest index, so decrease the number of cliques
6367                 */
6368                if( i == consdata->nvars )
6369                   --(consdata->ncliques);
6370             }
6371             /* if the old clique number was smaller than the new one we have to check the front for an element with
6372              * clique number minus 1 */
6373             else if( oldcliqenum < consdata->cliquepartition[pos] )
6374             {
6375                cliquenumbefore = consdata->cliquepartition[pos] - 1;
6376                for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6377 
6378                if( i < cliquenumbefore )
6379                   consdata->cliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6380             }
6381             /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6382             else if( pos == consdata->nvars - 1)
6383             {
6384                cliquenumbefore = consdata->cliquepartition[pos];
6385                for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->cliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6386 
6387                if( i < cliquenumbefore )
6388                   --(consdata->ncliques);
6389             }
6390             /* if the old clique number is equal to the new one the cliquepartition should be ok */
6391          }
6392       }
6393       else
6394          --(consdata->ncliques);
6395    }
6396 
6397    if( consdata->negcliquepartitioned )
6398    {
6399       assert(consdata->negcliquepartition != NULL);
6400       /* if the clique number is equal to the number of variables we have only cliques with one element, so we don't
6401        * change the clique number */
6402       if( consdata->negcliquepartition[consdata->nvars-1] != consdata->nvars - 1 )
6403       {
6404          int oldcliqenum;
6405 
6406          oldcliqenum = consdata->negcliquepartition[pos];
6407          consdata->negcliquepartition[pos] = consdata->negcliquepartition[consdata->nvars-1];
6408 
6409          /* the following if and else cases assure that we have increasing clique numbers */
6410          if( consdata->negcliquepartition[pos] > pos )
6411             consdata->negcliquepartitioned = FALSE; /* recalculate the clique partition after a coefficient was removed */
6412          else
6413          {
6414             int i;
6415             int cliquenumbefore;
6416 
6417             /* if the old clique number was greater than the new one we have to check that, before a bigger clique number
6418              * occurs, the same as the old one occurs */
6419             if( oldcliqenum > consdata->negcliquepartition[pos] )
6420             {
6421                for( i = 0; i < consdata->nvars; ++i )
6422                   if( oldcliqenum == consdata->negcliquepartition[i] )
6423                      break;
6424                   else if( oldcliqenum < consdata->negcliquepartition[i] )
6425                   {
6426                      consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6427                      break;
6428                   }
6429                /* if we reached the end in the for loop, it means we have deleted the last element of the clique with
6430                 * the biggest index, so decrease the number of negated cliques
6431                 */
6432                if( i == consdata->nvars )
6433                   --(consdata->nnegcliques);
6434             }
6435             /* if the old clique number was smaller than the new one we have to check the front for an element with
6436              * clique number minus 1 */
6437             else if( oldcliqenum < consdata->negcliquepartition[pos] )
6438             {
6439                cliquenumbefore = consdata->negcliquepartition[pos] - 1;
6440                for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6441 
6442                if( i < cliquenumbefore )
6443                   consdata->negcliquepartitioned = FALSE; /* recalculate the negated clique partition after a coefficient was removed */
6444             }
6445             /* if we deleted the last element of the clique with biggest index, we have to decrease the clique number */
6446             else if( pos == consdata->nvars - 1)
6447             {
6448                cliquenumbefore = consdata->negcliquepartition[pos];
6449                for( i = pos - 1; i >= 0 && i >= cliquenumbefore && consdata->negcliquepartition[i] < cliquenumbefore; --i ); /*lint !e722*/
6450 
6451                if( i < cliquenumbefore )
6452                   --(consdata->nnegcliques);
6453             }
6454             /* otherwise if the old clique number is equal to the new one the cliquepartition should be ok */
6455          }
6456       }
6457       else
6458          --(consdata->nnegcliques);
6459    }
6460 
6461    --(consdata->nvars);
6462 
6463    return SCIP_OKAY;
6464 }
6465 
6466 /** removes all items with weight zero from knapsack constraint */
6467 static
removeZeroWeights(SCIP * scip,SCIP_CONS * cons)6468 SCIP_RETCODE removeZeroWeights(
6469    SCIP*                 scip,               /**< SCIP data structure */
6470    SCIP_CONS*            cons                /**< knapsack constraint */
6471    )
6472 {
6473    SCIP_CONSDATA* consdata;
6474    int v;
6475 
6476    consdata = SCIPconsGetData(cons);
6477    assert(consdata != NULL);
6478 
6479    for( v = consdata->nvars-1; v >= 0; --v )
6480    {
6481       if( consdata->weights[v] == 0 )
6482       {
6483          SCIP_CALL( delCoefPos(scip, cons, v) );
6484       }
6485    }
6486 
6487    return SCIP_OKAY;
6488 }
6489 
6490 /* perform deletion of variables in all constraints of the constraint handler */
6491 static
performVarDeletions(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss)6492 SCIP_RETCODE performVarDeletions(
6493    SCIP*                 scip,               /**< SCIP data structure */
6494    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6495    SCIP_CONS**           conss,              /**< array of constraints */
6496    int                   nconss              /**< number of constraints */
6497    )
6498 {
6499    SCIP_CONSDATA* consdata;
6500    int i;
6501    int v;
6502 
6503    assert(scip != NULL);
6504    assert(conshdlr != NULL);
6505    assert(conss != NULL);
6506    assert(nconss >= 0);
6507    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6508 
6509    /* iterate over all constraints */
6510    for( i = 0; i < nconss; i++ )
6511    {
6512       consdata = SCIPconsGetData(conss[i]);
6513 
6514       /* constraint is marked, that some of its variables were deleted */
6515       if( consdata->varsdeleted )
6516       {
6517          /* iterate over all variables of the constraint and delete them from the constraint */
6518          for( v = consdata->nvars - 1; v >= 0; --v )
6519          {
6520             if( SCIPvarIsDeleted(consdata->vars[v]) )
6521             {
6522                SCIP_CALL( delCoefPos(scip, conss[i], v) );
6523             }
6524          }
6525          consdata->varsdeleted = FALSE;
6526       }
6527    }
6528 
6529    return SCIP_OKAY;
6530 }
6531 
6532 /** replaces multiple occurrences of a variable or its negation by a single coefficient */
6533 static
mergeMultiples(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff)6534 SCIP_RETCODE mergeMultiples(
6535    SCIP*                 scip,               /**< SCIP data structure */
6536    SCIP_CONS*            cons,               /**< knapsack constraint */
6537    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off */
6538    )
6539 {
6540    SCIP_CONSDATA* consdata;
6541    int v;
6542    int prev;
6543 
6544    assert(scip != NULL);
6545    assert(cons != NULL);
6546    assert(cutoff != NULL);
6547 
6548    consdata = SCIPconsGetData(cons);
6549    assert(consdata != NULL);
6550 
6551    *cutoff = FALSE;
6552 
6553    if( consdata->merged )
6554       return SCIP_OKAY;
6555 
6556    if( consdata->nvars <= 1 )
6557    {
6558       consdata->merged = TRUE;
6559       return SCIP_OKAY;
6560    }
6561 
6562    assert(consdata->vars != NULL || consdata->nvars == 0);
6563 
6564    /* sorting array after indices of variables, that's only for faster merging */
6565    SCIPsortPtrPtrLongIntInt((void**)consdata->vars, (void**)consdata->eventdata, consdata->weights,
6566       consdata->cliquepartition, consdata->negcliquepartition, SCIPvarCompActiveAndNegated, consdata->nvars);
6567 
6568    /* knapsack-sorting (decreasing weights) now lost */
6569    consdata->sorted = FALSE;
6570 
6571    v = consdata->nvars - 1;
6572    prev = v - 1;
6573    /* loop backwards through the items: deletion only affects rear items */
6574    while( prev >= 0 )
6575    {
6576       SCIP_VAR* var1;
6577       SCIP_VAR* var2;
6578       SCIP_Bool negated1;
6579       SCIP_Bool negated2;
6580 
6581       negated1 = FALSE;
6582       negated2 = FALSE;
6583 
6584       var1 = consdata->vars[v];
6585       assert(SCIPvarIsBinary(var1));
6586       assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED);
6587       if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED )
6588       {
6589          var1 = SCIPvarGetNegatedVar(var1);
6590          negated1 = TRUE;
6591       }
6592       assert(var1 != NULL);
6593 
6594       var2 = consdata->vars[prev];
6595       assert(SCIPvarIsBinary(var2));
6596       assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED);
6597       if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED )
6598       {
6599          var2 = SCIPvarGetNegatedVar(var2);
6600          negated2 = TRUE;
6601       }
6602       assert(var2 != NULL);
6603 
6604       if( var1 == var2 )
6605       {
6606          /* both variables are either active or negated */
6607          if( negated1 == negated2 )
6608          {
6609             /* variables var1 and var2 are equal: add weight of var1 to var2, and delete var1 */
6610             consdataChgWeight(consdata, prev, consdata->weights[v] + consdata->weights[prev]);
6611             SCIP_CALL( delCoefPos(scip, cons, v) );
6612          }
6613          /* variables var1 and var2 are opposite: subtract smaller weight from larger weight, reduce capacity,
6614           * and delete item of smaller weight
6615           */
6616          else if( consdata->weights[v] == consdata->weights[prev] )
6617          {
6618             /* both variables eliminate themselves: w*x + w*(1-x) == w */
6619             consdata->capacity -= consdata->weights[v];
6620             SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6621             SCIP_CALL( delCoefPos(scip, cons, prev) );
6622 
6623             --prev;
6624          }
6625          else if( consdata->weights[v] < consdata->weights[prev] )
6626          {
6627             consdata->capacity -= consdata->weights[v];
6628             consdataChgWeight(consdata, prev, consdata->weights[prev] - consdata->weights[v]);
6629             assert(consdata->weights[prev] > 0);
6630             SCIP_CALL( delCoefPos(scip, cons, v) ); /* this does not affect var2, because var2 stands before var1 */
6631          }
6632          else
6633          {
6634             consdata->capacity -= consdata->weights[prev];
6635             consdataChgWeight(consdata, v, consdata->weights[v] - consdata->weights[prev]);
6636             assert(consdata->weights[v] > 0);
6637             SCIP_CALL( delCoefPos(scip, cons, prev) ); /* attention: normally we lose our order */
6638             /* restore order iff necessary */
6639             if( consdata->nvars != v ) /* otherwise the order still stands */
6640             {
6641                assert(prev == 0 || ((prev > 0) && (SCIPvarIsActive(consdata->vars[prev - 1]) || SCIPvarGetStatus(consdata->vars[prev - 1]) == SCIP_VARSTATUS_NEGATED)) );
6642                /* either that was the last pair or both, the negated and "normal" variable in front doesn't match var1, so the order is irrelevant */
6643                if( prev == 0 || (var1 != consdata->vars[prev - 1] && var1 != SCIPvarGetNegatedVar(consdata->vars[prev - 1])) )
6644                   --prev;
6645                else /* we need to let v at the same position*/
6646                {
6647                   consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6648                   /* don't decrease v, the same variable may exist up front */
6649                   --prev;
6650                   continue;
6651                }
6652             }
6653          }
6654          consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
6655       }
6656       v = prev;
6657       --prev;
6658    }
6659 
6660    consdata->merged = TRUE;
6661 
6662    /* check infeasibility */
6663    if( consdata->onesweightsum > consdata->capacity )
6664    {
6665       SCIPdebugMsg(scip, "merge multiples detected cutoff.\n");
6666       *cutoff = TRUE;
6667       return SCIP_OKAY;
6668    }
6669 
6670    return SCIP_OKAY;
6671 }
6672 
6673 /** in case the knapsack constraint is independent of every else, solve the knapsack problem (exactly) and apply the
6674  *  fixings (dual reductions)
6675  */
6676 static
dualPresolving(SCIP * scip,SCIP_CONS * cons,int * nfixedvars,int * ndelconss,SCIP_Bool * deleted)6677 SCIP_RETCODE dualPresolving(
6678    SCIP*                 scip,               /**< SCIP data structure */
6679    SCIP_CONS*            cons,               /**< knapsack constraint */
6680    int*                  nfixedvars,         /**< pointer to count number of fixings */
6681    int*                  ndelconss,          /**< pointer to count number of deleted constraints  */
6682    SCIP_Bool*            deleted             /**< pointer to store if the constraint is deleted */
6683    )
6684 {
6685    SCIP_CONSDATA* consdata;
6686    SCIP_VAR** vars;
6687    SCIP_Real* profits;
6688    int* solitems;
6689    int* nonsolitems;
6690    int* items;
6691    SCIP_Real solval;
6692    SCIP_Bool infeasible;
6693    SCIP_Bool tightened;
6694    SCIP_Bool applicable;
6695    int nsolitems;
6696    int nnonsolitems;
6697    int nvars;
6698    int v;
6699 
6700    assert(!SCIPconsIsModifiable(cons));
6701 
6702    /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
6703     * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
6704     * added to the problems have the check flag set to FALSE
6705     */
6706    if( !SCIPconsIsChecked(cons) )
6707       return SCIP_OKAY;
6708 
6709    consdata = SCIPconsGetData(cons);
6710    assert(consdata != NULL);
6711 
6712    nvars = consdata->nvars;
6713    vars = consdata->vars;
6714 
6715    SCIP_CALL( SCIPallocBufferArray(scip, &profits, nvars) );
6716    SCIP_CALL( SCIPallocBufferArray(scip, &items, nvars) );
6717    SCIP_CALL( SCIPallocBufferArray(scip, &solitems, nvars) );
6718    SCIP_CALL( SCIPallocBufferArray(scip, &nonsolitems, nvars) );
6719 
6720    applicable = TRUE;
6721 
6722    /* check if we can apply the dual reduction; this can be done if the knapsack has the only locks on this constraint;
6723     * collect object values which are the profits of the knapsack problem
6724     */
6725    for( v = 0; v < nvars; ++v )
6726    {
6727       SCIP_VAR* var;
6728       SCIP_Bool negated;
6729 
6730       var = vars[v];
6731       assert(var != NULL);
6732 
6733       /* the variable should not be (globally) fixed */
6734       assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
6735 
6736       if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > 0
6737          || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > 1 )
6738       {
6739          applicable = FALSE;
6740          break;
6741       }
6742 
6743       negated = FALSE;
6744 
6745       /* get the active variable */
6746       SCIP_CALL( SCIPvarGetProbvarBinary(&var, &negated) );
6747       assert(SCIPvarIsActive(var));
6748 
6749       if( negated )
6750          profits[v] = SCIPvarGetObj(var);
6751       else
6752          profits[v] = -SCIPvarGetObj(var);
6753 
6754       SCIPdebugMsg(scip, "variable <%s> -> item size %" SCIP_LONGINT_FORMAT ", profit <%g>\n",
6755          SCIPvarGetName(vars[v]), consdata->weights[v], profits[v]);
6756       items[v] = v;
6757    }
6758 
6759    if( applicable )
6760    {
6761       SCIP_Bool success;
6762 
6763       SCIPdebugMsg(scip, "the knapsack constraint <%s> is independent to rest of the problem\n", SCIPconsGetName(cons));
6764       SCIPdebugPrintCons(scip, cons, NULL);
6765 
6766       /* solve knapsack problem exactly */
6767       SCIP_CALL( SCIPsolveKnapsackExactly(scip, consdata->nvars, consdata->weights, profits, consdata->capacity,
6768             items, solitems, nonsolitems, &nsolitems, &nnonsolitems, &solval, &success) );
6769 
6770       if( success )
6771       {
6772          SCIP_VAR* var;
6773 
6774          /* apply solution of the knapsack as dual reductions */
6775          for( v = 0; v < nsolitems; ++v )
6776          {
6777             var = vars[solitems[v]];
6778             assert(var != NULL);
6779 
6780             SCIPdebugMsg(scip, "variable <%s> only locked up in knapsack constraints: dual presolve <%s>[%.15g,%.15g] >= 1.0\n",
6781                SCIPvarGetName(var), SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
6782             SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, TRUE, &infeasible, &tightened) );
6783             assert(!infeasible);
6784             assert(tightened);
6785             (*nfixedvars)++;
6786          }
6787 
6788          for( v = 0; v < nnonsolitems; ++v )
6789          {
6790             var = vars[nonsolitems[v]];
6791             assert(var != NULL);
6792 
6793             SCIPdebugMsg(scip, "variable <%s> has no down locks: dual presolve <%s>[%.15g,%.15g] <= 0.0\n",
6794                SCIPvarGetName(var), SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
6795             SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, TRUE, &infeasible, &tightened) );
6796             assert(!infeasible);
6797             assert(tightened);
6798             (*nfixedvars)++;
6799          }
6800 
6801          SCIP_CALL( SCIPdelCons(scip, cons) );
6802          (*ndelconss)++;
6803          (*deleted) = TRUE;
6804       }
6805    }
6806 
6807    SCIPfreeBufferArray(scip, &nonsolitems);
6808    SCIPfreeBufferArray(scip, &solitems);
6809    SCIPfreeBufferArray(scip, &items);
6810    SCIPfreeBufferArray(scip, &profits);
6811 
6812    return SCIP_OKAY;
6813 }
6814 
6815 /** check if the knapsack constraint is parallel to objective function; if so update the cutoff bound and avoid that the
6816  *  constraint enters the LP by setting the initial and separated flag to FALSE
6817  */
6818 static
checkParallelObjective(SCIP * scip,SCIP_CONS * cons,SCIP_CONSHDLRDATA * conshdlrdata)6819 SCIP_RETCODE checkParallelObjective(
6820    SCIP*                 scip,               /**< SCIP data structure */
6821    SCIP_CONS*            cons,               /**< knapsack constraint */
6822    SCIP_CONSHDLRDATA*    conshdlrdata        /**< knapsack constraint handler data */
6823    )
6824 {
6825    SCIP_CONSDATA* consdata;
6826    SCIP_VAR** vars;
6827    SCIP_VAR* var;
6828    SCIP_Real offset;
6829    SCIP_Real scale;
6830    SCIP_Real objval;
6831    SCIP_Bool applicable;
6832    SCIP_Bool negated;
6833    int nobjvars;
6834    int nvars;
6835    int v;
6836 
6837    assert(scip != NULL);
6838    assert(cons != NULL);
6839    assert(conshdlrdata != NULL);
6840 
6841    consdata = SCIPconsGetData(cons);
6842    assert(consdata != NULL);
6843 
6844    nvars = consdata->nvars;
6845    nobjvars = SCIPgetNObjVars(scip);
6846 
6847    /* check if the knapsack constraints has the same number of variables as the objective function and if the initial
6848     * and/or separated flag is set to FALSE
6849     */
6850    if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
6851       return SCIP_OKAY;
6852 
6853    /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant. Since we
6854     * have a pure feasibility problem, we do not want to set a cutoff or lower bound.
6855     */
6856    if( nobjvars == 0 )
6857       return SCIP_OKAY;
6858 
6859    vars = consdata->vars;
6860    assert(vars != NULL);
6861 
6862    applicable = TRUE;
6863    offset = 0.0;
6864    scale = 1.0;
6865 
6866    for( v = 0; v < nvars && applicable; ++v )
6867    {
6868       negated = FALSE;
6869       var = vars[v];
6870       assert(var != NULL);
6871 
6872       if( SCIPvarIsNegated(var) )
6873       {
6874          negated = TRUE;
6875          var = SCIPvarGetNegatedVar(var);
6876          assert(var != NULL);
6877       }
6878 
6879       objval = SCIPvarGetObj(var);
6880 
6881       /* if a variable has a zero objective coefficient the knapsack constraint is not parallel to objective function */
6882       if( SCIPisZero(scip, objval) )
6883          applicable = FALSE;
6884       else
6885       {
6886          SCIP_Real weight;
6887 
6888          weight = (SCIP_Real)consdata->weights[v];
6889 
6890          if( negated )
6891          {
6892             if( v == 0 )
6893             {
6894                /* the first variable defines the scale */
6895                scale = weight / -objval;
6896 
6897                offset += weight;
6898             }
6899             else if( SCIPisEQ(scip, -objval * scale, weight) )
6900                offset += weight;
6901             else
6902                applicable = FALSE;
6903          }
6904          else if( v == 0 )
6905          {
6906             /* the first variable define the scale */
6907             scale = weight / objval;
6908          }
6909          else if( !SCIPisEQ(scip, objval * scale, weight) )
6910             applicable = FALSE;
6911       }
6912    }
6913 
6914    if( applicable )
6915    {
6916       if( SCIPisPositive(scip, scale) && conshdlrdata->detectcutoffbound )
6917       {
6918          SCIP_Real cutoffbound;
6919 
6920          /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6921          SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6922          SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6923 
6924          cutoffbound = (consdata->capacity - offset) / scale;
6925 
6926          SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6927             SCIPconsGetName(cons), cutoffbound);
6928 
6929          /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are
6930           * still excepted
6931           */
6932          cutoffbound += SCIPcutoffbounddelta(scip);
6933 
6934          SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a cutoff bound <%g>\n",
6935             SCIPconsGetName(cons), cutoffbound);
6936 
6937          if( cutoffbound < SCIPgetCutoffbound(scip) )
6938          {
6939             SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
6940 
6941             SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
6942          }
6943          else
6944          {
6945             /* in case the cutoff bound is worse then currently known one we avoid additionaly enforcement and
6946              * propagation
6947              */
6948             SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
6949             SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
6950          }
6951       }
6952       else if( SCIPisNegative(scip, scale) && conshdlrdata->detectlowerbound )
6953       {
6954          SCIP_Real lowerbound;
6955 
6956          /* avoid that the knapsack constraint enters the LP since it is parallel to the objective function */
6957          SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
6958          SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
6959 
6960          lowerbound = (consdata->capacity - offset) / scale;
6961 
6962          SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provids a lower bound <%g>\n",
6963             SCIPconsGetName(cons), lowerbound);
6964 
6965          SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
6966       }
6967    }
6968 
6969    return SCIP_OKAY;
6970 }
6971 
6972 /** sort the variables and weights w.r.t. the clique partition; thereby ensure the current order of the variables when a
6973  *  weight of one variable is greater or equal another weight and both variables are in the same cliques */
6974 static
stableSort(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR ** vars,SCIP_Longint * weights,int * cliquestartposs,SCIP_Bool usenegatedclique)6975 SCIP_RETCODE stableSort(
6976    SCIP*                 scip,               /**< SCIP data structure */
6977    SCIP_CONSDATA*        consdata,           /**< knapsack constraint data */
6978    SCIP_VAR**            vars,               /**< array for sorted variables */
6979    SCIP_Longint*         weights,            /**< array for sorted weights */
6980    int*                  cliquestartposs,    /**< starting position array for each clique */
6981    SCIP_Bool             usenegatedclique    /**< should negated or normal clique partition be used */
6982    )
6983 {
6984    SCIP_VAR** origvars;
6985    int norigvars;
6986    SCIP_Longint* origweights;
6987    int* cliquepartition;
6988    int ncliques;
6989 
6990    SCIP_VAR*** varpointers;
6991    SCIP_Longint** weightpointers;
6992    int* cliquecount;
6993 
6994    int nextpos;
6995    int c;
6996    int v;
6997 
6998    assert(scip != NULL);
6999    assert(consdata != NULL);
7000    assert(vars != NULL);
7001    assert(weights != NULL);
7002    assert(cliquestartposs != NULL);
7003 
7004    origweights = consdata->weights;
7005    origvars = consdata->vars;
7006    norigvars = consdata->nvars;
7007 
7008    assert(origvars != NULL || norigvars == 0);
7009    assert(origweights != NULL || norigvars == 0);
7010 
7011    if( norigvars == 0 )
7012       return SCIP_OKAY;
7013 
7014    if( usenegatedclique )
7015    {
7016       assert(consdata->negcliquepartitioned);
7017 
7018       cliquepartition = consdata->negcliquepartition;
7019       ncliques = consdata->nnegcliques;
7020    }
7021    else
7022    {
7023       assert(consdata->cliquepartitioned);
7024 
7025       cliquepartition = consdata->cliquepartition;
7026       ncliques = consdata->ncliques;
7027    }
7028 
7029    assert(cliquepartition != NULL);
7030    assert(ncliques > 0);
7031 
7032    /* we first count all clique items and alloc temporary memory for a bucket sort */
7033    SCIP_CALL( SCIPallocBufferArray(scip, &cliquecount, ncliques) );
7034    BMSclearMemoryArray(cliquecount, ncliques);
7035 
7036    /* first we count for each clique the number of elements */
7037    for( v = norigvars - 1; v >= 0; --v )
7038    {
7039       assert(0 <= cliquepartition[v] && cliquepartition[v] < ncliques);
7040       ++(cliquecount[cliquepartition[v]]);
7041    }
7042 
7043    /*@todo: maybe it is better to put largest cliques up front */
7044 
7045 #ifndef NDEBUG
7046    BMSclearMemoryArray(vars, norigvars);
7047    BMSclearMemoryArray(weights, norigvars);
7048 #endif
7049    SCIP_CALL( SCIPallocBufferArray(scip, &varpointers, ncliques) );
7050    SCIP_CALL( SCIPallocBufferArray(scip, &weightpointers, ncliques) );
7051 
7052    nextpos = 0;
7053    /* now we initialize all start pointers for each clique, so they will be ordered */
7054    for( c = 0; c < ncliques; ++c )
7055    {
7056       /* to reach the goal that all variables of each clique will be standing next to each other we will initialize the
7057        * starting pointers for each clique by adding the number of each clique to the last clique starting pointer
7058        * e.g. clique1 has 4 elements and clique2 has 3 elements the the starting pointer for clique1 will be the pointer
7059        *      to vars[0], the starting pointer to clique2 will be the pointer to vars[4] and to clique3 it will be
7060        *      vars[7]
7061        *
7062        */
7063       varpointers[c] = (SCIP_VAR**) (vars + nextpos);
7064       cliquestartposs[c] = nextpos;
7065       weightpointers[c] = (SCIP_Longint*) (weights + nextpos);
7066       assert(cliquecount[c] > 0);
7067       nextpos += cliquecount[c];
7068       assert(nextpos > 0);
7069    }
7070    assert(nextpos == norigvars);
7071    cliquestartposs[c] = nextpos;
7072 
7073    /* now we copy all variable and weights to the right order */
7074    for( v = 0; v < norigvars; ++v )
7075    {
7076       *(varpointers[cliquepartition[v]]) = origvars[v];  /*lint !e613*/
7077       ++(varpointers[cliquepartition[v]]);
7078       *(weightpointers[cliquepartition[v]]) = origweights[v];  /*lint !e613*/
7079       ++(weightpointers[cliquepartition[v]]);
7080    }
7081 #ifndef NDEBUG
7082    for( v = 0; v < norigvars; ++v )
7083    {
7084       assert(vars[v] != NULL);
7085       assert(weights[v] > 0);
7086    }
7087 #endif
7088 
7089    /* free temporary memory */
7090    SCIPfreeBufferArray(scip, &weightpointers);
7091    SCIPfreeBufferArray(scip, &varpointers);
7092    SCIPfreeBufferArray(scip, &cliquecount);
7093 
7094    return SCIP_OKAY;
7095 }
7096 
7097 /** deletes all fixed variables from knapsack constraint, and replaces variables with binary representatives */
7098 static
applyFixings(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff)7099 SCIP_RETCODE applyFixings(
7100    SCIP*                 scip,               /**< SCIP data structure */
7101    SCIP_CONS*            cons,               /**< knapsack constraint */
7102    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off, or NULL if this
7103                                               *   information is not needed; in this case, we apply all fixings
7104                                               *   instead of stopping after the first infeasible one */
7105    )
7106 {
7107    SCIP_CONSDATA* consdata;
7108    int v;
7109 
7110    assert(scip != NULL);
7111    assert(cons != NULL);
7112 
7113    consdata = SCIPconsGetData(cons);
7114    assert(consdata != NULL);
7115    assert(consdata->nvars == 0 || consdata->vars != NULL);
7116 
7117    if( cutoff != NULL )
7118       *cutoff = FALSE;
7119 
7120    SCIPdebugMsg(scip, "apply fixings:\n");
7121    SCIPdebugPrintCons(scip, cons, NULL);
7122 
7123    /* check infeasibility */
7124    if ( consdata->onesweightsum > consdata->capacity )
7125    {
7126       SCIPdebugMsg(scip, "apply fixings detected cutoff.\n");
7127 
7128       if( cutoff != NULL )
7129          *cutoff = TRUE;
7130 
7131       return SCIP_OKAY;
7132    }
7133 
7134    /* all multi-aggregations should be resolved */
7135    consdata->existmultaggr = FALSE;
7136 
7137    v = 0;
7138    while( v < consdata->nvars )
7139    {
7140       SCIP_VAR* var;
7141 
7142       var = consdata->vars[v];
7143       assert(SCIPvarIsBinary(var));
7144 
7145       if( SCIPvarGetLbGlobal(var) > 0.5 )
7146       {
7147          assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
7148          consdata->capacity -= consdata->weights[v];
7149          SCIP_CALL( delCoefPos(scip, cons, v) );
7150          consdata->cliquesadded = FALSE; /* reduced capacity might lead to larger cliques */
7151       }
7152       else if( SCIPvarGetUbGlobal(var) < 0.5 )
7153       {
7154          assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
7155          SCIP_CALL( delCoefPos(scip, cons, v) );
7156       }
7157       else
7158       {
7159          SCIP_VAR* repvar;
7160          SCIP_VAR* negvar;
7161          SCIP_VAR* workvar;
7162          SCIP_Longint weight;
7163          SCIP_Bool negated;
7164 
7165          weight = consdata->weights[v];
7166 
7167          /* get binary representative of variable */
7168          SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
7169          assert(repvar != NULL);
7170 
7171          /* check for multi-aggregation */
7172          if( SCIPvarIsNegated(repvar) )
7173          {
7174             workvar = SCIPvarGetNegatedVar(repvar);
7175             assert(workvar != NULL);
7176             negated = TRUE;
7177          }
7178          else
7179          {
7180             workvar = repvar;
7181             negated = FALSE;
7182          }
7183 
7184          /* @todo maybe resolve the problem that the eliminating of the multi-aggregation leads to a non-knapsack
7185           * constraint (converting into a linear constraint), for example the multi-aggregation consist of a non-binary
7186           * variable or due to resolving now their are non-integral coefficients or a non-integral capacity
7187           *
7188           * If repvar is not negated so workvar = repvar, otherwise workvar = 1 - repvar. This means,
7189           * weight * workvar = weight * (a_1*y_1 + ... + a_n*y_n + c)
7190           *
7191           * The explanation for  the following block:
7192           * 1a) If repvar is a multi-aggregated variable weight * repvar should be replaced by
7193           *     weight * (a_1*y_1 + ... + a_n*y_n + c).
7194           * 1b) If repvar is a negated variable of a multi-aggregated variable weight * repvar should be replaced by
7195           *     weight - weight * (a_1*y_1 + ... + a_n*y_n + c), for better further use here we switch the sign of weight
7196           *     so now we have the replacement -weight + weight * (a_1*y_1 + ... + a_n*y_n + c).
7197           * 2)  For all replacement variable we check:
7198           * 2a) weight * a_i < 0 than we add -weight * a_i * y_i_neg to the constraint and adjust the capacity through
7199           *     capacity -= weight * a_i caused by the negation of y_i.
7200           * 2b) weight * a_i >= 0 than we add weight * a_i * y_i to the constraint.
7201           * 3a) If repvar was not negated we need to subtract weight * c from capacity.
7202           * 3b) If repvar was negated we need to subtract weight * (c - 1) from capacity(note we switched the sign of
7203           *     weight in this case.
7204           */
7205          if( SCIPvarGetStatus(workvar) == SCIP_VARSTATUS_MULTAGGR )
7206          {
7207             SCIP_VAR** aggrvars;
7208             SCIP_Real* aggrscalars;
7209             SCIP_Real aggrconst;
7210             int naggrvars;
7211             int i;
7212 
7213             SCIP_CALL( SCIPflattenVarAggregationGraph(scip, workvar) );
7214             naggrvars = SCIPvarGetMultaggrNVars(workvar);
7215             aggrvars = SCIPvarGetMultaggrVars(workvar);
7216             aggrscalars = SCIPvarGetMultaggrScalars(workvar);
7217             aggrconst = SCIPvarGetMultaggrConstant(workvar);
7218             assert((aggrvars != NULL && aggrscalars != NULL) || naggrvars == 0);
7219 
7220             if( !SCIPisIntegral(scip, weight * aggrconst) )
7221             {
7222                SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrconst = %g\n", weight*aggrconst);
7223                return SCIP_ERROR;
7224             }
7225 
7226             /* if workvar was negated, we have to flip the weight */
7227             if( negated )
7228                weight *= -1;
7229 
7230             for( i = naggrvars - 1; i >= 0; --i )
7231             {
7232                assert(aggrvars != NULL);
7233                assert(aggrscalars != NULL);
7234 
7235                if( !SCIPvarIsBinary(aggrvars[i]) )
7236                {
7237                   SCIPerrorMessage("try to resolve a multi-aggregation with a non-binary %svariable <%s> with bounds [%g,%g]\n",
7238                      SCIPvarIsIntegral(aggrvars[i]) ? "integral " : "", SCIPvarGetName(aggrvars[i]),  SCIPvarGetLbGlobal(aggrvars[i]), SCIPvarGetUbGlobal(aggrvars[i]));
7239                   return SCIP_ERROR;
7240                }
7241                if( !SCIPisIntegral(scip, weight * aggrscalars[i]) )
7242                {
7243                   SCIPerrorMessage("try to resolve a multi-aggregation with a non-integral value for weight*aggrscalars = %g\n", weight*aggrscalars[i]);
7244                   return SCIP_ERROR;
7245                }
7246                /* if the new coefficient is smaller than zero, we need to add the negated variable instead and adjust the capacity */
7247                if( SCIPisNegative(scip, weight * aggrscalars[i]) )
7248                {
7249                   SCIP_CALL( SCIPgetNegatedVar(scip, aggrvars[i], &negvar));
7250                   assert(negvar != NULL);
7251                   SCIP_CALL( addCoef(scip, cons, negvar, (SCIP_Longint)(SCIPfloor(scip, -weight * aggrscalars[i] + 0.5))) );
7252                   consdata->capacity -= (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5));
7253                }
7254                else
7255                {
7256                   SCIP_CALL( addCoef(scip, cons, aggrvars[i], (SCIP_Longint)(SCIPfloor(scip, weight * aggrscalars[i] + 0.5))) );
7257                }
7258             }
7259             /* delete old coefficient */
7260             SCIP_CALL( delCoefPos(scip, cons, v) );
7261 
7262             /* adjust the capacity with the aggregation constant and if necessary the extra weight through the negation */
7263             if( negated )
7264                consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * (aggrconst - 1) + 0.5);
7265             else
7266                consdata->capacity -= (SCIP_Longint)SCIPfloor(scip, weight * aggrconst + 0.5);
7267 
7268             if( consdata->capacity < 0 )
7269             {
7270                if( cutoff != NULL )
7271                {
7272                   *cutoff = TRUE;
7273                   break;
7274                }
7275             }
7276          }
7277          /* check, if the variable should be replaced with the representative */
7278          else if( repvar != var )
7279          {
7280             /* delete old (aggregated) variable */
7281             SCIP_CALL( delCoefPos(scip, cons, v) );
7282 
7283             /* add representative instead */
7284             SCIP_CALL( addCoef(scip, cons, repvar, weight) );
7285          }
7286          else
7287             ++v;
7288       }
7289    }
7290    assert(consdata->onesweightsum == 0);
7291 
7292    SCIPdebugMsg(scip, "after applyFixings, before merging:\n");
7293    SCIPdebugPrintCons(scip, cons, NULL);
7294 
7295    /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have to
7296     * clean up the constraint
7297     */
7298    if( cutoff != NULL && !(*cutoff) )
7299    {
7300       SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
7301       SCIPdebugMsg(scip, "after applyFixings and merging:\n");
7302       SCIPdebugPrintCons(scip, cons, NULL);
7303    }
7304 
7305    return SCIP_OKAY;
7306 }
7307 
7308 
7309 /** propagation method for knapsack constraints */
7310 static
propagateCons(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,SCIP_Bool * redundant,int * nfixedvars,SCIP_Bool usenegatedclique)7311 SCIP_RETCODE propagateCons(
7312    SCIP*                 scip,               /**< SCIP data structure */
7313    SCIP_CONS*            cons,               /**< knapsack constraint */
7314    SCIP_Bool*            cutoff,             /**< pointer to store whether the node can be cut off */
7315    SCIP_Bool*            redundant,          /**< pointer to store whether constraint is redundant */
7316    int*                  nfixedvars,         /**< pointer to count number of fixings */
7317    SCIP_Bool             usenegatedclique    /**< should negated clique information be used */
7318    )
7319 {
7320    SCIP_CONSDATA* consdata;
7321    SCIP_Bool infeasible;
7322    SCIP_Bool tightened;
7323    SCIP_Longint* secondmaxweights;
7324    SCIP_Longint minweightsum;
7325    SCIP_Longint residualcapacity;
7326 
7327    int nvars;
7328    int i;
7329    int nnegcliques;
7330 
7331    SCIP_VAR** myvars;
7332    SCIP_Longint* myweights;
7333    int* cliquestartposs;
7334    int* cliqueendposs;
7335    SCIP_Longint localminweightsum;
7336    SCIP_Bool foundmax;
7337    int c;
7338 
7339    assert(scip != NULL);
7340    assert(cons != NULL);
7341    assert(cutoff != NULL);
7342    assert(redundant != NULL);
7343    assert(nfixedvars != NULL);
7344 
7345    consdata = SCIPconsGetData(cons);
7346    assert(consdata != NULL);
7347 
7348    *cutoff = FALSE;
7349    *redundant = FALSE;
7350 
7351    SCIPdebugMsg(scip, "propagating knapsack constraint <%s>\n", SCIPconsGetName(cons));
7352 
7353    /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7354    if( !SCIPinRepropagation(scip) )
7355    {
7356       SCIP_CALL( SCIPincConsAge(scip, cons) );
7357    }
7358 
7359 #ifndef NDEBUG
7360    /* assert that only active or negated variables are present */
7361    for( i = 0; i < consdata->nvars && consdata->merged; ++i )
7362    {
7363       assert(SCIPvarIsActive(consdata->vars[i]) || SCIPvarIsNegated(consdata->vars[i]) || SCIPvarGetStatus(consdata->vars[i]) == SCIP_VARSTATUS_FIXED);
7364    }
7365 #endif
7366 
7367    usenegatedclique = usenegatedclique && consdata->merged;
7368 
7369    /* init for debugging */
7370    myvars = NULL;
7371    myweights = NULL;
7372    cliquestartposs = NULL;
7373    secondmaxweights = NULL;
7374    minweightsum = 0;
7375    nvars = consdata->nvars;
7376    /* make sure, the items are sorted by non-increasing weight */
7377    sortItems(consdata);
7378 
7379    do
7380    {
7381       localminweightsum = 0;
7382 
7383       /* (1) compute the minimum weight of the knapsack constraint using negated clique information;
7384        *     a negated clique means, that at most one of the clique variables can be zero
7385        *     - minweightsum = sum_{negated cliques C} ( sum(wi : i \in C) - W_max(C) ), where W_max(C) is the maximal weight of C
7386        *
7387        *     if for i \in C (a negated clique) oneweightsum + minweightsum - wi + W_max(C) > capacity => xi = 1
7388        *     since replacing i with the element of maximal weight leads to infeasibility
7389        */
7390       if( usenegatedclique && nvars > 0 )
7391       {
7392          SCIP_CONSHDLRDATA* conshdlrdata;
7393          conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7394          assert(conshdlrdata != NULL);
7395 
7396          /* compute clique partitions */
7397          SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
7398          nnegcliques = consdata->nnegcliques;
7399 
7400          /* if we have no real negated cliques we can stop here */
7401          if( nnegcliques == nvars )
7402          {
7403             /* run the standard algorithm that does not involve cliques */
7404             usenegatedclique = FALSE;
7405             break;
7406          }
7407 
7408          /* allocate temporary memory and initialize it */
7409          SCIP_CALL( SCIPduplicateBufferArray(scip, &myvars, consdata->vars, nvars) );
7410          SCIP_CALL( SCIPduplicateBufferArray(scip, &myweights, consdata->weights, nvars) ) ;
7411          SCIP_CALL( SCIPallocBufferArray(scip, &cliquestartposs, nnegcliques + 1) );
7412          SCIP_CALL( SCIPallocBufferArray(scip, &cliqueendposs, nnegcliques) );
7413          SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
7414          BMSclearMemoryArray(secondmaxweights, nnegcliques);
7415 
7416          /* resort variables to avoid quadratic algorithm later on */
7417          SCIP_CALL( stableSort(scip, consdata, myvars, myweights, cliquestartposs, TRUE) );
7418 
7419          /* save the end positions of the cliques because start positions are moved in the following loop */
7420          for( c = 0; c < nnegcliques; ++c )
7421          {
7422             cliqueendposs[c] = cliquestartposs[c+1] - 1;
7423             assert(cliqueendposs[c] - cliquestartposs[c] >= 0);
7424          }
7425 
7426          c = 0;
7427          foundmax = FALSE;
7428          i = 0;
7429 
7430          while( i < nvars )
7431          {
7432             /* ignore variables of the negated clique which are fixed to one since these are counted in
7433              * consdata->onesweightsum
7434              */
7435 
7436             /* if there are only one variable negated cliques left we can stop */
7437             if( nnegcliques - c == nvars - i )
7438             {
7439                minweightsum += localminweightsum;
7440                localminweightsum = 0;
7441                break;
7442             }
7443 
7444             /* for summing up the minimum active weights due to cliques we have to omit the biggest weights of each
7445              * clique, we can only skip this clique if this variables is not fixed to zero, otherwise we have to fix all
7446              * other clique variables to one
7447              */
7448             if( cliquestartposs[c] == i )
7449             {
7450                assert(myweights[i] > 0);
7451                ++c;
7452                minweightsum += localminweightsum;
7453                localminweightsum = 0;
7454                foundmax = TRUE;
7455 
7456                if( SCIPvarGetLbLocal(myvars[i]) > 0.5 )
7457                   foundmax = FALSE;
7458 
7459                if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7460                {
7461                   ++i;
7462                   continue;
7463                }
7464             }
7465 
7466             if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7467             {
7468                assert(myweights[i] > 0);
7469 
7470                if( SCIPvarGetUbLocal(myvars[i]) > 0.5 )
7471                {
7472                   assert(myweights[i] <= myweights[cliquestartposs[c - 1]]);
7473 
7474                   if( !foundmax )
7475                   {
7476                      foundmax = TRUE;
7477 
7478                      /* overwrite cliquestartpos to the position of the first unfixed variable in this clique */
7479                      cliquestartposs[c - 1] = i;
7480                      ++i;
7481 
7482                      continue;
7483                   }
7484                   /* memorize second max weight for each clique */
7485                   if( secondmaxweights[c - 1] == 0 )
7486                      secondmaxweights[c - 1] = myweights[i];
7487 
7488                   localminweightsum += myweights[i];
7489                }
7490                /* we found a fixed variable to zero so all other variables in this negated clique have to be fixed to one */
7491                else
7492                {
7493                   int v;
7494                   /* fix all other variables of the negated clique to 1 */
7495                   for( v = cliquestartposs[c - 1]; v < cliquestartposs[c]; ++v )
7496                   {
7497                      if( v != i && SCIPvarGetLbLocal(myvars[v]) < 0.5 )
7498                      {
7499                         SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[v]));
7500                         SCIP_CALL( SCIPinferBinvarCons(scip, myvars[v], TRUE, cons, SCIPvarGetIndex(myvars[i]), &infeasible, &tightened) );
7501 
7502                         if( infeasible )
7503                         {
7504                            assert( SCIPvarGetUbLocal(myvars[v]) < 0.5 );
7505 
7506                            /* analyze the infeasibility if conflict analysis is applicable */
7507                            if( SCIPisConflictAnalysisApplicable(scip) )
7508                            {
7509                               /* conflict analysis can only be applied in solving stage */
7510                               assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
7511 
7512                               /* initialize the conflict analysis */
7513                               SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
7514 
7515                               /* add the two variables which are fixed to zero within a negated clique */
7516                               SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[i]) );
7517                               SCIP_CALL( SCIPaddConflictBinvar(scip, myvars[v]) );
7518 
7519                               /* start the conflict analysis */
7520                               SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7521                            }
7522                            *cutoff = TRUE;
7523                            break;
7524                         }
7525                         assert(tightened);
7526                         ++(*nfixedvars);
7527                         SCIP_CALL( SCIPresetConsAge(scip, cons) );
7528                      }
7529                   }
7530 
7531                   /* reset local minweightsum for clique because all fixed to one variables are now counted in consdata->onesweightsum */
7532                   localminweightsum = 0;
7533                   /* we can jump to the end of this clique */
7534                   i = cliqueendposs[c - 1];
7535 
7536                   if( *cutoff )
7537                      break;
7538                }
7539             }
7540             ++i;
7541          }
7542          /* add last clique minweightsum */
7543          minweightsum += localminweightsum;
7544 
7545          SCIPdebugMsg(scip, "knapsack constraint <%s> has minimum weight sum of <%" SCIP_LONGINT_FORMAT ">\n",
7546             SCIPconsGetName(cons), minweightsum + consdata->onesweightsum );
7547 
7548          /* check, if weights of fixed variables don't exceeds knapsack capacity */
7549          if( !(*cutoff) && consdata->capacity >= minweightsum + consdata->onesweightsum )
7550          {
7551             SCIP_Longint maxcliqueweight = -1LL;
7552 
7553             /* loop over cliques */
7554             for( c = 0; c < nnegcliques; ++c )
7555             {
7556                SCIP_VAR* maxvar;
7557                SCIP_Bool maxvarfixed;
7558                int endvarposclique;
7559                int startvarposclique;
7560 
7561                assert(myvars != NULL);
7562                assert(nnegcliques == consdata->nnegcliques);
7563                assert(myweights != NULL);
7564                assert(secondmaxweights != NULL);
7565                assert(cliquestartposs != NULL);
7566 
7567                endvarposclique = cliqueendposs[c];
7568                startvarposclique = cliquestartposs[c];
7569 
7570                maxvar = myvars[startvarposclique];
7571 
7572                /* no need to process this negated clique because all variables are already fixed (which we detect from a fixed maxvar) */
7573                if( SCIPvarGetUbLocal(maxvar) - SCIPvarGetLbLocal(maxvar) < 0.5 )
7574                   continue;
7575 
7576                maxcliqueweight = myweights[startvarposclique];
7577                maxvarfixed = FALSE;
7578                /* if the sum of all weights of fixed variables to one plus the minimalweightsum (minimal weight which is already
7579                 * used in this knapsack due to negated cliques) plus any weight minus the second largest weight in this clique
7580                 * exceeds the capacity the maximum weight variable can be fixed to zero.
7581                 */
7582                if( consdata->onesweightsum + minweightsum  + (maxcliqueweight - secondmaxweights[c]) > consdata->capacity )
7583                {
7584 #ifndef NDEBUG
7585                   SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7586 #endif
7587                   assert(maxcliqueweight >= secondmaxweights[c]);
7588                   assert(SCIPvarGetLbLocal(maxvar) < 0.5 && SCIPvarGetUbLocal(maxvar) > 0.5);
7589 
7590                   SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(maxvar));
7591                   SCIP_CALL( SCIPresetConsAge(scip, cons) );
7592                   SCIP_CALL( SCIPinferBinvarCons(scip, maxvar, FALSE, cons, cliquestartposs[c], &infeasible, &tightened) );
7593                   assert(consdata->onesweightsum == oldonesweightsum);
7594                   assert(!infeasible);
7595                   assert(tightened);
7596                   (*nfixedvars)++;
7597                   maxvarfixed = TRUE;
7598                }
7599                /* the remaining cliques are singletons such that all subsequent variables have a weight that
7600                 * fits into the knapsack
7601                 */
7602                else if( nnegcliques - c == nvars - startvarposclique )
7603                   break;
7604                /* early termination of the remaining loop because no further variable fixings are possible:
7605                 *
7606                 * the gain in any of the following negated cliques (the additional term if the maximum weight variable was set to 1, and the second
7607                 * largest was set to 0) does not suffice to infer additional variable fixings because
7608                 *
7609                 * - the cliques are sorted by decreasing maximum weight -> for all c' >= c: maxweights[c'] <= maxcliqueweight
7610                 * - their second largest elements are at least as large as the smallest weight of the knapsack
7611                 */
7612                else if( consdata->onesweightsum + minweightsum + (maxcliqueweight - consdata->weights[nvars - 1]) <= consdata->capacity )
7613                   break;
7614 
7615                /* loop over items with non-maximal weight (omitting the first position) */
7616                for( i = endvarposclique; i > startvarposclique; --i )
7617                {
7618                   /* there should be no variable fixed to 0 between startvarposclique + 1 and endvarposclique unless we
7619                    * messed up the clique preprocessing in the previous loop to filter those variables out */
7620                   assert(SCIPvarGetUbLocal(myvars[i]) > 0.5);
7621 
7622                   /* only check variables of negated cliques for which no variable is locally fixed */
7623                   if( SCIPvarGetLbLocal(myvars[i]) < 0.5 )
7624                   {
7625                      assert(maxcliqueweight >= myweights[i]);
7626                      assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7627 
7628                      /* we fix the members of this clique with non-maximal weight in two cases to 1:
7629                       *
7630                       * the maxvar was already fixed to 0 because it has a huge gain.
7631                       *
7632                       * if for i \in C (a negated clique) onesweightsum - wi + W_max(c) > capacity  => xi = 1
7633                       * since replacing i with the element of maximal weight leads to infeasibility */
7634                      if( maxvarfixed || consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity  )
7635                      {
7636 #ifndef NDEBUG
7637                         SCIP_Longint oldonesweightsum = consdata->onesweightsum;
7638 #endif
7639                         SCIPdebugMsg(scip, " -> fixing variable <%s> to 1, due to negated clique information\n", SCIPvarGetName(myvars[i]));
7640                         SCIP_CALL( SCIPinferBinvarCons(scip, myvars[i], TRUE, cons, -i, &infeasible, &tightened) );
7641                         assert(consdata->onesweightsum == oldonesweightsum + myweights[i]);
7642                         assert(!infeasible);
7643                         assert(tightened);
7644                         ++(*nfixedvars);
7645                         SCIP_CALL( SCIPresetConsAge(scip, cons) );
7646 
7647                         /* update minweightsum because now the variable is fixed to one and its weight is counted by
7648                          * consdata->onesweightsum
7649                          */
7650                         minweightsum -= myweights[i];
7651                         assert(minweightsum >= 0);
7652                      }
7653                      else
7654                         break;
7655                   }
7656                }
7657 #ifndef NDEBUG
7658                /* in debug mode, we assert that we did not miss possible fixings by the break above */
7659                for( ; i > startvarposclique; --i )
7660                {
7661                   SCIP_Bool varisfixed = SCIPvarGetUbLocal(myvars[i]) - SCIPvarGetLbLocal(myvars[i]) < 0.5;
7662                   SCIP_Bool exceedscapacity = consdata->onesweightsum + minweightsum - myweights[i] + maxcliqueweight > consdata->capacity;
7663 
7664                   assert(i == endvarposclique || myweights[i] >= myweights[i+1]);
7665                   assert(varisfixed || !exceedscapacity);
7666                }
7667 #endif
7668             }
7669          }
7670          SCIPfreeBufferArray(scip, &secondmaxweights);
7671          SCIPfreeBufferArray(scip, &cliqueendposs);
7672          SCIPfreeBufferArray(scip, &cliquestartposs);
7673          SCIPfreeBufferArray(scip, &myweights);
7674          SCIPfreeBufferArray(scip, &myvars);
7675       }
7676 
7677       assert(consdata->negcliquepartitioned || minweightsum == 0);
7678    }
7679    while( FALSE );
7680 
7681    assert(usenegatedclique || minweightsum == 0);
7682    /* check, if weights of fixed variables already exceed knapsack capacity */
7683    if( consdata->capacity < minweightsum + consdata->onesweightsum )
7684    {
7685       SCIPdebugMsg(scip, " -> cutoff - fixed weight: %" SCIP_LONGINT_FORMAT ", capacity: %" SCIP_LONGINT_FORMAT " \n",
7686          consdata->onesweightsum, consdata->capacity);
7687 
7688       SCIP_CALL( SCIPresetConsAge(scip, cons) );
7689       *cutoff = TRUE;
7690 
7691       /* analyze the cutoff in SOLVING stage and if conflict analysis is turned on */
7692       if( (SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip)) && SCIPisConflictAnalysisApplicable(scip) )
7693       {
7694          /* start conflict analysis with the fixed-to-one variables, add only as many as needed to exceed the capacity */
7695          SCIP_Longint weight;
7696 
7697          weight = 0;
7698 
7699          SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
7700 
7701          for( i = 0; i < nvars && weight <= consdata->capacity; i++ )
7702          {
7703             if( SCIPvarGetLbLocal(consdata->vars[i]) > 0.5)
7704             {
7705                SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
7706                weight += consdata->weights[i];
7707             }
7708          }
7709 
7710          SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7711       }
7712 
7713       return SCIP_OKAY;
7714    }
7715 
7716    /* the algorithm below is a special case of propagation involving negated cliques */
7717    if( !usenegatedclique )
7718    {
7719       assert(consdata->sorted);
7720       residualcapacity = consdata->capacity - consdata->onesweightsum;
7721 
7722       /* fix all variables to zero, that don't fit into the knapsack anymore */
7723       for( i = 0; i < nvars && consdata->weights[i] > residualcapacity; ++i )
7724       {
7725          /* if all weights of fixed variables to one plus any weight exceeds the capacity the variables have to be fixed
7726           * to zero
7727           */
7728          if( SCIPvarGetLbLocal(consdata->vars[i]) < 0.5 )
7729          {
7730             if( SCIPvarGetUbLocal(consdata->vars[i]) > 0.5 )
7731             {
7732                assert(consdata->onesweightsum + consdata->weights[i] > consdata->capacity);
7733                SCIPdebugMsg(scip, " -> fixing variable <%s> to 0\n", SCIPvarGetName(consdata->vars[i]));
7734                SCIP_CALL( SCIPresetConsAge(scip, cons) );
7735                SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[i], FALSE, cons, i, &infeasible, &tightened) );
7736                assert(!infeasible);
7737                assert(tightened);
7738                (*nfixedvars)++;
7739             }
7740          }
7741       }
7742    }
7743 
7744    /* check if the knapsack is now redundant */
7745    if( !SCIPconsIsModifiable(cons) )
7746    {
7747       SCIP_Longint unfixedweightsum = consdata->onesweightsum;
7748 
7749       /* sum up the weights of all unfixed variables, plus the weight sum of all variables fixed to one already */
7750       for( i = 0; i < nvars; ++i )
7751       {
7752          if( SCIPvarGetLbLocal(consdata->vars[i]) + 0.5 < SCIPvarGetUbLocal(consdata->vars[i]) )
7753          {
7754             unfixedweightsum += consdata->weights[i];
7755 
7756             /* the weight sum is larger than the capacity, so the constraint is not redundant */
7757             if( unfixedweightsum > consdata->capacity )
7758                return SCIP_OKAY;
7759          }
7760       }
7761       /* we summed up all (unfixed and fixed to one) weights and did not exceed the capacity, so the constraint is redundant */
7762       SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", unfixedweightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
7763          SCIPconsGetName(cons), consdata->weightsum, unfixedweightsum, consdata->capacity);
7764       SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7765       *redundant = TRUE;
7766    }
7767 
7768    return SCIP_OKAY;
7769 }
7770 
7771 /** all but one variable fit into the knapsack constraint, so we can upgrade this constraint to an logicor constraint
7772  *  containing all negated variables of this knapsack constraint
7773  */
7774 static
upgradeCons(SCIP * scip,SCIP_CONS * cons,int * ndelconss,int * naddconss)7775 SCIP_RETCODE upgradeCons(
7776    SCIP*                 scip,               /**< SCIP data structure */
7777    SCIP_CONS*            cons,               /**< knapsack constraint */
7778    int*                  ndelconss,          /**< pointer to store the amount of deleted constraints */
7779    int*                  naddconss           /**< pointer to count number of added constraints */
7780    )
7781 {
7782    SCIP_CONS* newcons;
7783    SCIP_CONSDATA* consdata;
7784 
7785    assert(scip != NULL);
7786    assert(cons != NULL);
7787    assert(ndelconss != NULL);
7788    assert(naddconss != NULL);
7789 
7790    consdata = SCIPconsGetData(cons);
7791    assert(consdata != NULL);
7792    assert(consdata->nvars > 1);
7793 
7794    /* if the knapsack constraint consists only of two variables, we can upgrade it to a set-packing constraint */
7795    if( consdata->nvars == 2 )
7796    {
7797       SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
7798 
7799       SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
7800             SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7801             SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
7802             SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
7803             SCIPconsIsStickingAtNode(cons)) );
7804    }
7805    /* if the knapsack constraint consists of at least three variables, we can upgrade it to a logicor constraint
7806     * containing all negated variables of the knapsack
7807     */
7808    else
7809    {
7810       SCIP_VAR** consvars;
7811 
7812       SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a logicor constraint", SCIPconsGetName(cons));
7813 
7814       SCIP_CALL( SCIPallocBufferArray(scip, &consvars, consdata->nvars) );
7815       SCIP_CALL( SCIPgetNegatedVars(scip, consdata->nvars, consdata->vars, consvars) );
7816 
7817       SCIP_CALL( SCIPcreateConsLogicor(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consvars,
7818             SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7819             SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
7820             SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
7821             SCIPconsIsStickingAtNode(cons)) );
7822 
7823       SCIPfreeBufferArray(scip, &consvars);
7824    }
7825 
7826    SCIP_CALL( SCIPaddCons(scip, newcons) );
7827    SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7828    ++(*naddconss);
7829 
7830    SCIP_CALL( SCIPdelCons(scip, cons) );
7831    ++(*ndelconss);
7832 
7833    return SCIP_OKAY;
7834 }
7835 
7836 /** delete redundant variables
7837  *
7838  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13   =>   x4, x5 always fits into the knapsack, so we can delete them
7839  *
7840  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
7841  *      =>   x4, x5 always fits into the knapsack, so we can delete them
7842  *
7843  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
7844  *      =>   we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
7845  */
7846 static
deleteRedundantVars(SCIP * scip,SCIP_CONS * cons,SCIP_Longint frontsum,int splitpos,int * nchgcoefs,int * nchgsides,int * naddconss)7847 SCIP_RETCODE deleteRedundantVars(
7848    SCIP*                 scip,               /**< SCIP data structure */
7849    SCIP_CONS*            cons,               /**< knapsack constraint */
7850    SCIP_Longint          frontsum,           /**< sum of front items which fit if we try to take from the first till the last */
7851    int                   splitpos,           /**< split position till when all front items are fitting, splitpos is the
7852                                               *   first which did not fit */
7853    int*                  nchgcoefs,          /**< pointer to store the amount of changed coefficients */
7854    int*                  nchgsides,          /**< pointer to store the amount of changed sides */
7855    int*                  naddconss           /**< pointer to count number of added constraints */
7856    )
7857 {
7858    SCIP_CONSHDLRDATA* conshdlrdata;
7859    SCIP_CONSDATA* consdata;
7860    SCIP_VAR** vars;
7861    SCIP_Longint* weights;
7862    SCIP_Longint capacity;
7863    SCIP_Longint gcd;
7864    int nvars;
7865    int w;
7866 
7867    assert(scip != NULL);
7868    assert(cons != NULL);
7869    assert(nchgcoefs != NULL);
7870    assert(nchgsides != NULL);
7871    assert(naddconss != NULL);
7872 
7873    consdata = SCIPconsGetData(cons);
7874    assert(consdata != NULL);
7875    assert(0 < frontsum && frontsum < consdata->weightsum);
7876    assert(0 < splitpos && splitpos < consdata->nvars);
7877 
7878    conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
7879    assert(conshdlrdata != NULL);
7880 
7881    vars = consdata->vars;
7882    weights = consdata->weights;
7883    nvars = consdata->nvars;
7884    capacity = consdata->capacity;
7885 
7886    /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7887     * weight must not be sorted by their index
7888     */
7889 #ifndef NDEBUG
7890    for( w = nvars - 1; w > 0; --w )
7891       assert(weights[w] <= weights[w-1]);
7892 #endif
7893 
7894    /* if there are no variables rear to splitpos, the constraint has no redundant variables */
7895    if( consdata->nvars - 1 == splitpos )
7896       return SCIP_OKAY;
7897 
7898    assert(frontsum + weights[splitpos] > capacity);
7899 
7900    /* detect redundant variables */
7901    if( consdata->weightsum - weights[splitpos] <= capacity )
7902    {
7903       /* all rear items are redundant, because leaving one item in front and incl. of splitpos out the rear itmes always
7904        * fit
7905        */
7906       SCIPdebugMsg(scip, "Found redundant variables in constraint <%s>.\n", SCIPconsGetName(cons));
7907 
7908       /* delete items and update capacity */
7909       for( w = nvars - 1; w > splitpos; --w )
7910       {
7911          consdata->capacity -= weights[w];
7912          SCIP_CALL( delCoefPos(scip, cons, w) );
7913       }
7914       assert(w == splitpos);
7915 
7916       ++(*nchgsides);
7917       *nchgcoefs += (nvars - splitpos);
7918 
7919       /* division by greatest common divisor */
7920       gcd = weights[w];
7921       for( ; w >= 0 && gcd > 1; --w )
7922       {
7923          gcd = SCIPcalcGreComDiv(gcd, weights[w]);
7924       }
7925 
7926       /* normalize if possible */
7927       if( gcd > 1 )
7928       {
7929          for( w = splitpos; w >= 0; --w )
7930          {
7931             consdataChgWeight(consdata, w, weights[w]/gcd);
7932          }
7933          (*nchgcoefs) += nvars;
7934 
7935          consdata->capacity /= gcd;
7936          ++(*nchgsides);
7937       }
7938 
7939       /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
7940        * weight must not be sorted by their index
7941        */
7942 #ifndef NDEBUG
7943       for( w = consdata->nvars - 1; w > 0; --w )
7944          assert(weights[w] <= weights[w - 1]);
7945 #endif
7946    }
7947    /* rear items can only be redundant, when the sum is smaller to the weight at splitpos and all rear items would
7948     * always fit into the knapsack, therefor the item directly after splitpos needs to be smaller than the one at
7949     * splitpos and needs to fit into the knapsack
7950     */
7951    else if( conshdlrdata->disaggregation && frontsum + weights[splitpos + 1] <= capacity )
7952    {
7953       int* clqpart;
7954       int nclq;
7955       int len;
7956 
7957       len = nvars - (splitpos + 1);
7958       /* allocate temporary memory */
7959       SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
7960 
7961       /* calculate clique partition */
7962       SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[splitpos+1]), len, clqpart, &nclq) );
7963 
7964       /* check if we found at least one clique */
7965       if( nclq < len )
7966       {
7967          SCIP_Longint maxactduetoclq;
7968          int cliquenum;
7969 
7970          maxactduetoclq = 0;
7971          cliquenum = 0;
7972 
7973          /* calculate maximum activity due to cliques */
7974          for( w = 0; w < len; ++w )
7975          {
7976             assert(clqpart[w] >= 0 && clqpart[w] <= w);
7977             if( clqpart[w] == cliquenum )
7978             {
7979                maxactduetoclq += weights[w + splitpos + 1];
7980                ++cliquenum;
7981             }
7982          }
7983 
7984          /* all rear items are redundant due to clique information, if maxactduetoclq is smaller than the weight before,
7985           * so delete them and create for all clique the corresponding clique constraints and update the capacity
7986           */
7987          if( frontsum + maxactduetoclq <= capacity )
7988          {
7989             SCIP_VAR** clqvars;
7990             int nclqvars;
7991             int c;
7992 
7993             assert(maxactduetoclq < weights[splitpos]);
7994 
7995             SCIPdebugMsg(scip, "Found redundant variables in constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
7996 
7997             /* allocate temporary memory */
7998             SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, len - nclq + 1) );
7999 
8000             for( c = 0; c < nclq; ++c )
8001             {
8002                nclqvars = 0;
8003                for( w = 0; w < len; ++w )
8004                {
8005                   if( clqpart[w] == c )
8006                   {
8007                      clqvars[nclqvars] = vars[w + splitpos + 1];
8008                      ++nclqvars;
8009                   }
8010                }
8011 
8012                /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8013                if( nclqvars > 1 )
8014                {
8015                   SCIP_CONS* cliquecons;
8016                   char name[SCIP_MAXSTRLEN];
8017 
8018                   (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8019                   SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8020                         SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
8021                         SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
8022                         SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
8023                         SCIPconsIsStickingAtNode(cons)) );
8024                   SCIPdebugMsg(scip, " -> adding clique constraint: ");
8025                   SCIPdebugPrintCons(scip, cliquecons, NULL);
8026                   SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8027                   SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8028                   ++(*naddconss);
8029                }
8030             }
8031 
8032             /* delete items and update capacity */
8033             for( w = nvars - 1; w > splitpos; --w )
8034             {
8035                SCIP_CALL( delCoefPos(scip, cons, w) );
8036                ++(*nchgcoefs);
8037             }
8038             consdata->capacity -= maxactduetoclq;
8039             assert(frontsum <= consdata->capacity);
8040             ++(*nchgsides);
8041 
8042             assert(w == splitpos);
8043 
8044             /* renew weights pointer */
8045             weights = consdata->weights;
8046 
8047             /* division by greatest common divisor */
8048             gcd = weights[w];
8049             for( ; w >= 0 && gcd > 1; --w )
8050             {
8051                gcd = SCIPcalcGreComDiv(gcd, weights[w]);
8052             }
8053 
8054             /* normalize if possible */
8055             if( gcd > 1 )
8056             {
8057                for( w = splitpos; w >= 0; --w )
8058                {
8059                   consdataChgWeight(consdata, w, weights[w]/gcd);
8060                }
8061                (*nchgcoefs) += nvars;
8062 
8063                consdata->capacity /= gcd;
8064                ++(*nchgsides);
8065             }
8066 
8067             /* free temporary memory */
8068             SCIPfreeBufferArray(scip, &clqvars);
8069 
8070             /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8071              * weight must not be sorted by their index
8072              */
8073 #ifndef NDEBUG
8074             for( w = consdata->nvars - 1; w > 0; --w )
8075                assert(weights[w] <= weights[w - 1]);
8076 #endif
8077          }
8078       }
8079 
8080       /* free temporary memory */
8081       SCIPfreeBufferArray(scip, &clqpart);
8082    }
8083 
8084    return SCIP_OKAY;
8085 }
8086 
8087 /* detect redundant variables which always fits into the knapsack
8088  *
8089  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 13   =>   x4, x5 always fits into the knapsack, so we can delete them
8090  *
8091  * i.e. 5x1 + 5x2 + 5x3 + 2x4 + 1x5 <= 8 and we have the cliqueinformation (x1,x2,x3) is a clique
8092  *      =>   x4, x5 always fits into the knapsack, so we can delete them
8093  *
8094  * i.e. 5x1 + 5x2 + 5x3 + 1x4 + 1x5 <= 6 and we have the cliqueinformation (x1,x2,x3) is a clique and (x4,x5) too
8095  *      =>   we create the set partitioning constraint x4 + x5 <= 1 and delete them in this knapsack
8096  */
8097 static
detectRedundantVars(SCIP * scip,SCIP_CONS * cons,int * ndelconss,int * nchgcoefs,int * nchgsides,int * naddconss)8098 SCIP_RETCODE detectRedundantVars(
8099    SCIP*                 scip,               /**< SCIP data structure */
8100    SCIP_CONS*            cons,               /**< knapsack constraint */
8101    int*                  ndelconss,          /**< pointer to store the amount of deleted constraints */
8102    int*                  nchgcoefs,          /**< pointer to store the amount of changed coefficients */
8103    int*                  nchgsides,          /**< pointer to store the amount of changed sides */
8104    int*                  naddconss           /**< pointer to count number of added constraints */
8105    )
8106 {
8107    SCIP_CONSHDLRDATA* conshdlrdata;
8108    SCIP_CONSDATA* consdata;
8109    SCIP_VAR** vars;
8110    SCIP_Longint* weights;
8111    SCIP_Longint capacity;
8112    SCIP_Longint sum;
8113    int noldchgcoefs;
8114    int nvars;
8115    int v;
8116    int w;
8117 
8118    assert(scip != NULL);
8119    assert(cons != NULL);
8120    assert(ndelconss != NULL);
8121    assert(nchgcoefs != NULL);
8122    assert(nchgsides != NULL);
8123    assert(naddconss != NULL);
8124 
8125    consdata = SCIPconsGetData(cons);
8126    assert(consdata != NULL);
8127    assert(consdata->nvars >= 2);
8128    assert(consdata->weightsum > consdata->capacity);
8129 
8130    noldchgcoefs = *nchgcoefs;
8131    vars = consdata->vars;
8132    weights = consdata->weights;
8133    nvars = consdata->nvars;
8134    capacity = consdata->capacity;
8135    sum = 0;
8136 
8137    /* search for maximal fitting items */
8138    for( v = 0; v < nvars && sum + weights[v] <= capacity; ++v )
8139       sum += weights[v];
8140 
8141    assert(v < nvars);
8142 
8143    /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8144    if( v == nvars - 1 )
8145    {
8146       SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8147       assert(SCIPconsIsDeleted(cons));
8148 
8149       return SCIP_OKAY;
8150    }
8151 
8152    if( v < nvars - 1 )
8153    {
8154       /* try to delete variables */
8155       SCIP_CALL( deleteRedundantVars(scip, cons, sum, v, nchgcoefs, nchgsides, naddconss) );
8156       assert(consdata->nvars > 1);
8157 
8158       /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8159       if( v == consdata->nvars - 1 )
8160       {
8161          SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8162          assert(SCIPconsIsDeleted(cons));
8163       }
8164 
8165       return SCIP_OKAY;
8166    }
8167 
8168    /* if we already found some redundant variables, stop here */
8169    if( *nchgcoefs > noldchgcoefs )
8170       return SCIP_OKAY;
8171 
8172    assert(vars == consdata->vars);
8173    assert(weights == consdata->weights);
8174    assert(nvars == consdata->nvars);
8175    assert(capacity == consdata->capacity);
8176 
8177    conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
8178    assert(conshdlrdata != NULL);
8179    /* calculate clique partition */
8180    SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
8181 
8182    /* check for real existing cliques */
8183    if( consdata->cliquepartition[v] < v )
8184    {
8185       SCIP_Longint sumfront;
8186       SCIP_Longint maxactduetoclqfront;
8187       int* clqpart;
8188       int cliquenum;
8189 
8190       sumfront = 0;
8191       maxactduetoclqfront = 0;
8192 
8193       clqpart = consdata->cliquepartition;
8194       cliquenum = 0;
8195 
8196       /* calculate maximal activity due to cliques */
8197       for( w = 0; w < nvars; ++w )
8198       {
8199          assert(clqpart[w] >= 0 && clqpart[w] <= w);
8200          if( clqpart[w] == cliquenum )
8201          {
8202             if( maxactduetoclqfront + weights[w] <= capacity )
8203             {
8204                maxactduetoclqfront += weights[w];
8205                ++cliquenum;
8206             }
8207             else
8208                break;
8209          }
8210          sumfront += weights[w];
8211       }
8212       assert(w >= v);
8213 
8214       /* if all items fit, then delete the whole constraint but create clique constraints which led to this
8215        * information
8216        */
8217       if( conshdlrdata->disaggregation && w == nvars )
8218       {
8219          SCIP_VAR** clqvars;
8220          int nclqvars;
8221          int c;
8222          int ncliques;
8223 
8224          assert(maxactduetoclqfront <= capacity);
8225 
8226          SCIPdebugMsg(scip, "Found redundant constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
8227 
8228          ncliques = consdata->ncliques;
8229 
8230          /* allocate temporary memory */
8231          SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, nvars - ncliques + 1) );
8232 
8233          for( c = 0; c < ncliques; ++c )
8234          {
8235             nclqvars = 0;
8236             for( w = 0; w < nvars; ++w )
8237             {
8238                if( clqpart[w] == c )
8239                {
8240                   clqvars[nclqvars] = vars[w];
8241                   ++nclqvars;
8242                }
8243             }
8244 
8245             /* we found a real clique so extract this constraint, because we do not know who this information generated so */
8246             if( nclqvars > 1 )
8247             {
8248                SCIP_CONS* cliquecons;
8249                char name[SCIP_MAXSTRLEN];
8250 
8251                (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), capacity, c);
8252                SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
8253                      SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
8254                      SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
8255                      SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
8256                      SCIPconsIsStickingAtNode(cons)) );
8257                SCIPdebugMsg(scip, " -> adding clique constraint: ");
8258                SCIPdebugPrintCons(scip, cliquecons, NULL);
8259                SCIP_CALL( SCIPaddCons(scip, cliquecons) );
8260                SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
8261                ++(*naddconss);
8262             }
8263          }
8264 
8265          /* delete old constraint */
8266          SCIP_CALL( SCIPdelConsLocal(scip, cons) );
8267          ++(*ndelconss);
8268 
8269          SCIPfreeBufferArray(scip, &clqvars);
8270 
8271          return SCIP_OKAY;
8272       }
8273 
8274       if( w > v && w < nvars - 1 )
8275       {
8276          /* try to delete variables */
8277          SCIP_CALL( deleteRedundantVars(scip, cons, sumfront, w, nchgcoefs, nchgsides, naddconss) );
8278       }
8279    }
8280 
8281    return SCIP_OKAY;
8282 }
8283 
8284 /** divides weights by their greatest common divisor and divides capacity by the same value, rounding down the result */
8285 static
normalizeWeights(SCIP_CONS * cons,int * nchgcoefs,int * nchgsides)8286 void normalizeWeights(
8287    SCIP_CONS*            cons,               /**< knapsack constraint */
8288    int*                  nchgcoefs,          /**< pointer to count total number of changed coefficients */
8289    int*                  nchgsides           /**< pointer to count number of side changes */
8290    )
8291 {
8292    SCIP_CONSDATA* consdata;
8293    SCIP_Longint gcd;
8294    int i;
8295 
8296    assert(nchgcoefs != NULL);
8297    assert(nchgsides != NULL);
8298    assert(!SCIPconsIsModifiable(cons));
8299 
8300    consdata = SCIPconsGetData(cons);
8301    assert(consdata != NULL);
8302    assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
8303    assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
8304    assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
8305    assert(consdata->nvars >= 1);
8306 
8307    /* sort items, because we can stop earlier if the smaller weights are evaluated first */
8308    sortItems(consdata);
8309 
8310    gcd = consdata->weights[consdata->nvars-1];
8311    for( i = consdata->nvars-2; i >= 0 && gcd >= 2; --i )
8312    {
8313       assert(SCIPvarGetLbLocal(consdata->vars[i]) < 0.5);
8314       assert(SCIPvarGetUbLocal(consdata->vars[i]) > 0.5); /* all fixed variables should have been removed */
8315 
8316       gcd = SCIPcalcGreComDiv(gcd, consdata->weights[i]);
8317    }
8318 
8319    if( gcd >= 2 )
8320    {
8321       SCIPdebugMessage("knapsack constraint <%s>: dividing weights by %" SCIP_LONGINT_FORMAT "\n", SCIPconsGetName(cons), gcd);
8322 
8323       for( i = 0; i < consdata->nvars; ++i )
8324       {
8325          consdataChgWeight(consdata, i, consdata->weights[i]/gcd);
8326       }
8327       consdata->capacity /= gcd;
8328       (*nchgcoefs) += consdata->nvars;
8329       (*nchgsides)++;
8330 
8331       /* weight should still be sorted, because the reduction preserves this */
8332 #ifndef NDEBUG
8333       for( i = consdata->nvars - 1; i > 0; --i )
8334          assert(consdata->weights[i] <= consdata->weights[i - 1]);
8335 #endif
8336       consdata->sorted = TRUE;
8337    }
8338 }
8339 
8340 /** dual weights tightening for knapsack constraints
8341  *
8342  *  1. a) check if all two pairs exceed the capacity, then we can upgrade this constraint to a set-packing constraint
8343  *     b) check if all but the smallest weight fit into the knapsack,  then we can upgrade this constraint to a logicor
8344  *        constraint
8345  *
8346  *  2. check if besides big coefficients, that fit only by itself, for a certain amount of variables all combination of
8347  *     these are a minimal cover, then might reduce the weights and the capacity, e.g.
8348  *
8349  *     +219y1 + 180y2 + 74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219  <=>  3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8350  *
8351  *  3. use the duality between a^Tx <= capacity   <=>   a^T~x >= weightsum - capacity to tighten weights, e.g.
8352  *
8353  *     11x1 + 10x2 + 7x3 + 7x4 + 5x5 <= 27    <=>   11~x1 + 10~x2 + 7~x3 + 7~x4 + 5~x5 >= 13
8354  *
8355  *     the above constraint can be changed to       8~x1 + 8~x2 + 6.5~x3 + 6.5~x4 + 5~x5 >= 13
8356  *
8357  *     16~x1 + 16~x2 + 13~x3 + 13~x4 + 10~x5 >= 26   <=>   16x1 + 16x2 + 13x3 + 13x4 + 10x5 <= 42
8358  */
8359 static
dualWeightsTightening(SCIP * scip,SCIP_CONS * cons,int * ndelconss,int * nchgcoefs,int * nchgsides,int * naddconss)8360 SCIP_RETCODE dualWeightsTightening(
8361    SCIP*                 scip,               /**< SCIP data structure */
8362    SCIP_CONS*            cons,               /**< knapsack constraint */
8363    int*                  ndelconss,          /**< pointer to store the amount of deleted constraints */
8364    int*                  nchgcoefs,          /**< pointer to store the amount of changed coefficients */
8365    int*                  nchgsides,          /**< pointer to store the amount of changed sides */
8366    int*                  naddconss           /**< pointer to count number of added constraints */
8367    )
8368 {
8369    SCIP_CONSDATA* consdata;
8370    SCIP_Longint* weights;
8371    SCIP_Longint dualcapacity;
8372    SCIP_Longint reductionsum;
8373    SCIP_Longint capacity;
8374    SCIP_Longint exceedsum;
8375    int oldnchgcoefs;
8376    int nvars;
8377    int vbig;
8378    int v;
8379    int w;
8380 #ifndef NDEBUG
8381    int oldnchgsides;
8382 #endif
8383 
8384    assert(scip != NULL);
8385    assert(cons != NULL);
8386    assert(ndelconss != NULL);
8387    assert(nchgcoefs != NULL);
8388    assert(nchgsides != NULL);
8389    assert(naddconss != NULL);
8390 
8391 #ifndef NDEBUG
8392    oldnchgsides = *nchgsides;
8393 #endif
8394 
8395    consdata = SCIPconsGetData(cons);
8396    assert(consdata != NULL);
8397    assert(consdata->weightsum > consdata->capacity);
8398    assert(consdata->nvars >= 2);
8399    assert(consdata->sorted);
8400 
8401    /* constraint should be merged */
8402    assert(consdata->merged);
8403 
8404    nvars = consdata->nvars;
8405    weights = consdata->weights;
8406    capacity = consdata->capacity;
8407 
8408    oldnchgcoefs = *nchgcoefs;
8409 
8410    /* case 1. */
8411    if( weights[nvars - 1] + weights[nvars - 2] > capacity )
8412    {
8413       SCIP_CONS* newcons;
8414 
8415       /* two variable are enough to exceed the constraint, so we can update it to a set-packing
8416        *
8417        * e.g. 5x1 + 4x2 + 3x3 <= 5   <=>    x1 + x2 + x3 <= 1
8418        */
8419       SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
8420 
8421       SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
8422             SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
8423             SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
8424             SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
8425             SCIPconsIsStickingAtNode(cons)) );
8426 
8427       SCIP_CALL( SCIPaddCons(scip, newcons) );
8428       SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
8429       ++(*naddconss);
8430 
8431       SCIP_CALL( SCIPdelCons(scip, cons) );
8432       ++(*ndelconss);
8433 
8434       return SCIP_OKAY;
8435    }
8436 
8437    /* all but one variable fit into the knapsack, so we can upgrade this constraint to a logicor */
8438    if( consdata->weightsum - weights[nvars - 1] <= consdata->capacity )
8439    {
8440       SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8441       assert(SCIPconsIsDeleted(cons));
8442 
8443       return SCIP_OKAY;
8444    }
8445 
8446    /* early termination, if the pair with biggest coeffcients together does not exceed the dualcapacity */
8447    /* @todo might be changed/removed when improving the coeffcients tightening */
8448    if( consdata->weightsum - capacity > weights[0] + weights[1] )
8449       return SCIP_OKAY;
8450 
8451    /* case 2. */
8452 
8453    v = 0;
8454 
8455    /* @todo generalize the following algorithm for several parts of the knapsack
8456     *
8457     * the following is done without looking at the dualcapacity; it is enough to check whether for a certain amount of
8458     * variables each combination is a minimal cover, some examples
8459     *
8460     * +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219     <=>    74~x1 + 70~x2 + 63~x3 + 62~x4 + 53~x5 >= 103
8461     *                                              <=>      ~x1 +   ~x2 +   ~x3 +   ~x4 +   ~x5 >= 2
8462     *                                              <=>       x1 +    x2 +    x3 +    x4 +    x5 <= 3
8463     *
8464     * +219y1 + 180y_2 +74x1 + 70x2 + 63x3 + 62x4 + 53x5 <= 219  <=>  3y1 + 3y2 + x1 + x2 + x3 + x4 + x5 <= 3
8465     *
8466     */
8467 
8468    /* determine big weights that fit only by itself */
8469    while( v < nvars && weights[v] + weights[nvars - 1] > capacity )
8470       ++v;
8471 
8472    vbig = v;
8473    assert(vbig < nvars - 1);
8474    exceedsum = 0;
8475 
8476    /* determine the amount needed to exceed the capacity */
8477    while( v < nvars && exceedsum <= capacity )
8478    {
8479       exceedsum += weights[v];
8480       ++v;
8481    }
8482 
8483    /* if we exceeded the capacity we might reduce the weights */
8484    if( exceedsum > capacity )
8485    {
8486       assert(vbig > 0 || v < nvars);
8487 
8488       /* all small weights were needed to exceed the capacity */
8489       if( v == nvars )
8490       {
8491          SCIP_Longint newweight = (SCIP_Longint)nvars - vbig - 1;
8492          assert(newweight > 0);
8493 
8494          /* reduce big weights */
8495          for( v = 0; v < vbig; ++v )
8496          {
8497             if( weights[v] > newweight )
8498             {
8499                consdataChgWeight(consdata, v, newweight);
8500                ++(*nchgcoefs);
8501             }
8502          }
8503 
8504          /* reduce small weights */
8505          for( ; v < nvars; ++v )
8506          {
8507             if( weights[v] > 1 )
8508             {
8509                consdataChgWeight(consdata, v, 1LL);
8510                ++(*nchgcoefs);
8511             }
8512          }
8513 
8514          consdata->capacity = newweight;
8515 
8516          /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8517           * weight must not be sorted by their index
8518           */
8519 #ifndef NDEBUG
8520          for( v = nvars - 1; v > 0; --v )
8521             assert(weights[v] <= weights[v-1]);
8522 #endif
8523 
8524          return SCIP_OKAY;
8525       }
8526       /* a certain amount of small variables exceed the capacity, so check if this holds for all combinations of the
8527        * small weights
8528        */
8529       else
8530       {
8531          SCIP_Longint exceedsumback = 0;
8532          int nexceed = v - vbig;
8533 
8534          assert(nexceed > 1);
8535 
8536          /* determine weightsum of the same amount as before but of the smallest weight */
8537          for( w = nvars - 1; w >= nvars - nexceed; --w )
8538             exceedsumback += weights[w];
8539 
8540          assert(w >= 0);
8541 
8542          /* if the same amount but with the smallest possible weights also exceed the capacity, it holds for all
8543           * combinations of all small weights
8544           */
8545          if( exceedsumback > capacity )
8546          {
8547             SCIP_Longint newweight = nexceed - 1;
8548 
8549             /* taking out the smallest element needs to fit */
8550             assert(exceedsumback - weights[nvars - 1] <= capacity);
8551 
8552             /* reduce big weights */
8553             for( v = 0; v < vbig; ++v )
8554             {
8555                if( weights[v] > newweight )
8556                {
8557                   consdataChgWeight(consdata, v, newweight);
8558                   ++(*nchgcoefs);
8559                }
8560             }
8561 
8562             /* reduce small weights */
8563             for( ; v < nvars; ++v )
8564             {
8565                if( weights[v] > 1 )
8566                {
8567                   consdataChgWeight(consdata, v, 1LL);
8568                   ++(*nchgcoefs);
8569                }
8570             }
8571 
8572             consdata->capacity = newweight;
8573 
8574             /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8575              * weight must not be sorted by their index
8576              */
8577 #ifndef NDEBUG
8578             for( v = nvars - 1; v > 0; --v )
8579                assert(weights[v] <= weights[v-1]);
8580 #endif
8581             return SCIP_OKAY;
8582          }
8583       }
8584    }
8585    else
8586    {
8587       /* if the following assert fails we have either a redundant constraint or a set-packing constraint, this should
8588        * not happen here
8589        */
8590       assert(vbig > 0 && vbig < nvars);
8591 
8592       /* either choose a big coefficients or all other variables
8593        *
8594        * 973x1 + 189x2 + 189x3 + 145x4 + 110x5 + 104x6 + 93x7 + 71x8 + 68x9 + 10x10 <= 979
8595        *
8596        * either choose x1, or all other variables (weightsum of x2 to x10 is 979 above), so we can tighten this
8597        * constraint to
8598        *
8599        * 9x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 <= 9
8600        */
8601 
8602       if( weights[vbig - 1] > (SCIP_Longint)nvars - vbig || weights[vbig] > 1 )
8603       {
8604          SCIP_Longint newweight = (SCIP_Longint)nvars - vbig;
8605 #ifndef NDEBUG
8606          SCIP_Longint resweightsum = consdata->weightsum;
8607 
8608          for( v = 0; v < vbig; ++v )
8609             resweightsum -= weights[v];
8610 
8611          assert(exceedsum == resweightsum);
8612 #endif
8613          assert(newweight > 0);
8614 
8615          /* reduce big weights */
8616          for( v = 0; v < vbig; ++v )
8617          {
8618             if( weights[v] > newweight )
8619             {
8620                consdataChgWeight(consdata, v, newweight);
8621                ++(*nchgcoefs);
8622             }
8623          }
8624 
8625          /* reduce small weights */
8626          for( ; v < nvars; ++v )
8627          {
8628             if( weights[v] > 1 )
8629             {
8630                consdataChgWeight(consdata, v, 1LL);
8631                ++(*nchgcoefs);
8632             }
8633          }
8634 
8635          consdata->capacity = newweight;
8636 
8637          /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8638           * weight must not be sorted by their index
8639           */
8640 #ifndef NDEBUG
8641          for( v = nvars - 1; v > 0; --v )
8642             assert(weights[v] <= weights[v-1]);
8643 #endif
8644          return SCIP_OKAY;
8645       }
8646    }
8647 
8648    /* case 3. */
8649 
8650    dualcapacity = consdata->weightsum - capacity;
8651    reductionsum = 0;
8652    v = 0;
8653 
8654    /* reduce big weights
8655     *
8656     * e.g. 11x0 + 11x1 + 10x2 + 10x3 <= 32   <=>    11~x0 + 11~x1 + 10~x2 + 10~x3 >= 10
8657     *                                        <=>    10~x0 + 10~x1 + 10~x2 + 10~x3 >= 10
8658     *                                        <=>       x0 +    x1 +    x2 +    x3 <= 3
8659     */
8660    while( weights[v] > dualcapacity )
8661    {
8662       reductionsum += (weights[v] - dualcapacity);
8663       consdataChgWeight(consdata, v, dualcapacity);
8664       ++v;
8665       assert(v < nvars);
8666    }
8667    (*nchgcoefs) += v;
8668 
8669    /* skip weights equal to the dualcapacity, because we cannot change them  */
8670    while( v < nvars && weights[v] == dualcapacity )
8671       ++v;
8672 
8673    /* any negated variable out of the first n - 1 items is enough to fulfill the constraint, so we can update it to a logicor
8674     * after a possible removal of the last, redundant item
8675     *
8676     * e.g. 10x1 + 10x2 + 10x3 <= 20   <=>    10~x1 + 10~x2 + 10~x3 >= 10  <=>   ~x1 + ~x2 + ~x3 >= 1
8677     */
8678    if( v >= nvars - 1 )
8679    {
8680       /* the last weight is not enough to satisfy the dual capacity -> remove this redundant item */
8681       if( v == nvars - 1 )
8682       {
8683          SCIP_CALL( delCoefPos(scip, cons, nvars - 1) );
8684       }
8685       SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8686       assert(SCIPconsIsDeleted(cons));
8687 
8688       return SCIP_OKAY;
8689    }
8690    else /* v < nvars - 1 <=> at least two items with weight smaller than the dual capacity */
8691    {
8692       /* @todo generalize the following algorithm for more than two variables */
8693 
8694       if( weights[nvars - 1] + weights[nvars - 2] >= dualcapacity )
8695       {
8696          /* we have a dual-knapsack constraint where we either need to choose one variable out of a subset (big
8697           * coefficients) of all or two variables of the rest
8698           *
8699           * e.g. 9x1 + 9x2 + 6x3 + 4x4 <= 19   <=>    9~x1 + 9~x2 + 6~x3 + 4~x4 >= 9
8700           *                                    <=>    2~x1 + 2~x2 +  ~x3 +  ~x4 >= 2
8701           *                                    <=>    2x1  +  2x2 +   x3 +   x4 <= 4
8702           *
8703           *      3x1 + 3x2 + 2x3 + 2x4 + 2x5 + 2x6 + x7 <= 12   <=>   3~x1 + 3~x2 + 2~x3 + 2~x4 + 2~x5 + 2~x6 + ~x7 >= 3
8704           *                                                     <=>   2~x1 + 2~x2 +  ~x3 +  ~x4 +  ~x5 +  ~x6 + ~x7 >= 2
8705           *                                                     <=>   2 x1 + 2 x2 +   x3 +   x4 +   x5 +   x6 +  x7 <= 7
8706           *
8707           */
8708          if( v > 0 && weights[nvars - 2] > 1 )
8709          {
8710             int ncoefchg = 0;
8711 
8712             /* reduce all bigger weights */
8713             for( w = 0; w < v; ++w )
8714             {
8715                if( weights[w] > 2 )
8716                {
8717                   consdataChgWeight(consdata, w, 2LL);
8718                   ++ncoefchg;
8719                }
8720                else
8721                {
8722                   assert(weights[0] == 2);
8723                   assert(weights[v - 1] == 2);
8724                   break;
8725                }
8726             }
8727 
8728             /* reduce all smaller weights */
8729             for( w = v; w < nvars; ++w )
8730             {
8731                if( weights[w] > 1 )
8732                {
8733                   consdataChgWeight(consdata, w, 1LL);
8734                   ++ncoefchg;
8735                }
8736             }
8737             assert(ncoefchg > 0);
8738 
8739             (*nchgcoefs) += ncoefchg;
8740 
8741             /* correct the capacity */
8742             consdata->capacity = (-2 + v * 2 + nvars - v); /*lint !e647*/
8743             assert(consdata->capacity > 0);
8744             assert(weights[0] <= consdata->capacity);
8745             assert(consdata->weightsum > consdata->capacity);
8746             /* reset the reductionsum */
8747             reductionsum = 0;
8748          }
8749          else if( v == 0 )
8750          {
8751             assert(weights[nvars - 2] == 1);
8752          }
8753       }
8754       else
8755       {
8756          SCIP_Longint minweight = weights[nvars - 1];
8757          SCIP_Longint newweight = dualcapacity - minweight;
8758          SCIP_Longint restsumweights = 0;
8759          SCIP_Longint sumcoef;
8760          SCIP_Bool sumcoefcase = FALSE;
8761          int startv = v;
8762          int end;
8763          int k;
8764 
8765          assert(weights[nvars - 1] + weights[nvars - 2] <= capacity);
8766 
8767          /* reduce big weights of pairs that exceed the dualcapacity
8768           *
8769           * e.g. 9x1 + 9x2 + 6x3 + 4x4 + 4x5 + 4x6 <= 27   <=>    9~x1 + 9~x2 + 6~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8770           *                                                <=>    9~x1 + 9~x2 + 5~x3 + 4~x4 + 4~x5 + 4~x6 >= 9
8771           *                                                <=>    9x1  + 9x2  + 5x3  + 4x4  + 4x5  + 4x6  <= 27
8772           */
8773          while( weights[v] > newweight )
8774          {
8775             reductionsum += (weights[v] - newweight);
8776             consdataChgWeight(consdata, v, newweight);
8777             ++v;
8778             assert(v < nvars);
8779          }
8780          (*nchgcoefs) += (v - startv);
8781 
8782          /* skip equal weights */
8783          while( weights[v] == newweight )
8784             ++v;
8785 
8786          if( v > 0 )
8787          {
8788             for( w = v; w < nvars; ++w )
8789                restsumweights += weights[w];
8790          }
8791          else
8792             restsumweights = consdata->weightsum;
8793 
8794          if( restsumweights < dualcapacity )
8795          {
8796             /* we found redundant variables, which does not influence the feasibility of any integral solution, e.g.
8797              *
8798              * +61x1  + 61x2  + 61x3  + 61x4  + 61x5  + 61x6  + 35x7  + 10x8 <= 350  <=>
8799              * +61~x1 + 61~x2 + 61~x3 + 61~x4 + 61~x5 + 61~x6 + 35~x7 + 10~x8 >= 61
8800              */
8801             if( startv == v )
8802             {
8803                /* remove redundant variables */
8804                for( w = nvars - 1; w >= v; --w )
8805                {
8806                   SCIP_CALL( delCoefPos(scip, cons, v) );
8807                   ++(*nchgcoefs);
8808                }
8809 
8810 #ifndef NDEBUG
8811                /* each coefficients should exceed the dualcapacity by itself */
8812                for( ; w >= 0; --w )
8813                   assert(weights[w] == dualcapacity);
8814 #endif
8815                /* for performance reasons we do not update the capacity(, i.e. reduce it by reductionsum) and directly
8816                 * upgrade this constraint
8817                 */
8818                SCIP_CALL( upgradeCons(scip, cons, ndelconss, naddconss) );
8819                assert(SCIPconsIsDeleted(cons));
8820 
8821                return SCIP_OKAY;
8822             }
8823 
8824             /* special case where we have three different coefficient types
8825              *
8826              * e.g. 9x1 + 9x2 + 6x3 + 6x4 + 4x5 + 4x6 <= 29   <=>    9~x1 + 9~x2 + 6~x3 + 6~x4 + 4~x5 + 4~x6 >= 9
8827              *                                                <=>    9~x1 + 9~x2 + 5~x3 + 5~x4 + 4~x5 + 4~x6 >= 9
8828              *                                                <=>    3~x1 + 3~x2 + 2~x3 + 2~x4 +  ~x5 +  ~x6 >= 3
8829              *                                                <=>    3x1  + 3x2  + 2x3  + 2x4  +   x5 +   x6 <= 9
8830              */
8831             if( weights[v] > 1 || (weights[startv] > (SCIP_Longint)nvars - v) || (startv > 0 && weights[0] == (SCIP_Longint)nvars - v + 1) )
8832             {
8833                SCIP_Longint newcap;
8834 
8835                /* adjust smallest coefficients, which all together do not exceed the dualcapacity */
8836                for( w = nvars - 1; w >= v; --w )
8837                {
8838                   if( weights[w] > 1 )
8839                   {
8840                      consdataChgWeight(consdata, w, 1LL);
8841                      ++(*nchgcoefs);
8842                   }
8843                }
8844 
8845                /* adjust middle sized coefficients, which when choosing also one small coefficients exceed the
8846                 * dualcapacity
8847                 */
8848                newweight = (SCIP_Longint)nvars - v;
8849                assert(newweight > 1);
8850                for( ; w >= startv; --w )
8851                {
8852                   if( weights[w] > newweight )
8853                   {
8854                      consdataChgWeight(consdata, w, newweight);
8855                      ++(*nchgcoefs);
8856                   }
8857                   else
8858                      assert(weights[w] == newweight);
8859                }
8860 
8861                /* adjust big sized coefficients, where each of them exceeds the dualcapacity by itself */
8862                ++newweight;
8863                assert(newweight > 2);
8864                for( ; w >= 0; --w )
8865                {
8866                   if( weights[w] > newweight )
8867                   {
8868                      consdataChgWeight(consdata, w, newweight);
8869                      ++(*nchgcoefs);
8870                   }
8871                   else
8872                      assert(weights[w] == newweight);
8873                }
8874 
8875                /* update the capacity */
8876                newcap = ((SCIP_Longint)startv - 1) * newweight + ((SCIP_Longint)v - startv) * (newweight - 1)  + ((SCIP_Longint)nvars - v);
8877                if( consdata->capacity > newcap )
8878                {
8879                   consdata->capacity = newcap;
8880                   ++(*nchgsides);
8881                }
8882                else
8883                   assert(consdata->capacity == newcap);
8884             }
8885             assert(weights[v] == 1 && (weights[startv] == (SCIP_Longint)nvars - v) && (startv == 0 || weights[0] == (SCIP_Longint)nvars - v + 1));
8886 
8887             /* the new dualcapacity should still be equal to the (nvars - v + 1) */
8888             assert(consdata->weightsum - consdata->capacity == (SCIP_Longint)nvars - v + 1);
8889 
8890             /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
8891              * weight must not be sorted by their index
8892              */
8893 #ifndef NDEBUG
8894             for( w = nvars - 1; w > 0; --w )
8895                assert(weights[w] <= weights[w - 1]);
8896 #endif
8897             return SCIP_OKAY;
8898          }
8899 
8900          /* check if all rear items have the same weight as the last one, so we cannot tighten the constraint further */
8901          end = nvars - 2;
8902          while( end >= 0 && weights[end] == weights[end + 1] )
8903          {
8904             assert(end >= v);
8905             --end;
8906          }
8907 
8908          if( v >= end )
8909             goto TERMINATE;
8910 
8911          end = nvars - 2;
8912 
8913          /* can we stop early, another special reduction case might exist */
8914          if( 2 * weights[end] > dualcapacity )
8915          {
8916             restsumweights = 0;
8917 
8918             /* determine capacity of the small items */
8919             for( w = end + 1; w < nvars; ++w )
8920                restsumweights += weights[w];
8921 
8922             if( restsumweights * 2 <= dualcapacity )
8923             {
8924                /* check for further posssible reductions in the middle */
8925                while( v < end && restsumweights + weights[v] >= dualcapacity )
8926                   ++v;
8927 
8928                if( v >= end )
8929                   goto TERMINATE;
8930 
8931                /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
8932                if( (dualcapacity & 1) == 0 )
8933                {
8934                   newweight = dualcapacity / 2;
8935 
8936                   /* set all middle coefficients */
8937                   for( ; v <= end; ++v )
8938                   {
8939                      if( weights[v] > newweight )
8940                      {
8941                         reductionsum += (weights[v] - newweight);
8942                         consdataChgWeight(consdata, v, newweight);
8943                         ++(*nchgcoefs);
8944                      }
8945                   }
8946                }
8947                /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
8948                 * other coefficients by 2
8949                 */
8950                else
8951                {
8952                   /* correct the reductionsum */
8953                   reductionsum *= 2;
8954 
8955                   /* multiply big coefficients by 2 */
8956                   for( w = 0; w < v; ++w )
8957                   {
8958                      consdataChgWeight(consdata, w, weights[w] * 2);
8959                   }
8960 
8961                   newweight = dualcapacity;
8962                   /* set all middle coefficients */
8963                   for( ; v <= end; ++v )
8964                   {
8965                      reductionsum += (2 * weights[v] - newweight);
8966                      consdataChgWeight(consdata, v, newweight);
8967                   }
8968 
8969                   /* multiply small coefficients by 2 */
8970                   for( w = end + 1; w < nvars; ++w )
8971                   {
8972                      consdataChgWeight(consdata, w, weights[w] * 2);
8973                   }
8974                   (*nchgcoefs) += nvars;
8975 
8976                   dualcapacity *= 2;
8977                   consdata->capacity *= 2;
8978                   ++(*nchgsides);
8979                }
8980             }
8981 
8982             goto TERMINATE;
8983          }
8984 
8985          /* further reductions using the next possible coefficient sum
8986           *
8987           * e.g. 9x1 + 8x2 + 7x3 + 3x4 + x5 <= 19   <=>    9~x1 + 8~x2 + 7~x3 + 3~x4 + ~x5 >= 9
8988           *                                         <=>    9~x1 + 8~x2 + 6~x3 + 3~x4 + ~x5 >= 9
8989           *                                         <=>    9x1  + 8x2  + 6x3  + 3x4  + x5  <= 18
8990           */
8991          /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
8992          for( k = 0; k < 4; ++k )
8993          {
8994             /* determine next minimal coefficient sum */
8995             switch( k )
8996             {
8997             case 0:
8998                sumcoef = weights[nvars - 1] + weights[nvars - 2];
8999                break;
9000             case 1:
9001                assert(nvars >= 3);
9002                sumcoef = weights[nvars - 1] + weights[nvars - 3];
9003                break;
9004             case 2:
9005                assert(nvars >= 4);
9006                if( weights[nvars - 1] + weights[nvars - 4] < weights[nvars - 2] + weights[nvars - 3] )
9007                {
9008                   sumcoefcase = TRUE;
9009                   sumcoef = weights[nvars - 1] + weights[nvars - 4];
9010                }
9011                else
9012                {
9013                   sumcoefcase = FALSE;
9014                   sumcoef = weights[nvars - 2] + weights[nvars - 3];
9015                }
9016                break;
9017             case 3:
9018                assert(nvars >= 5);
9019                if( sumcoefcase )
9020                {
9021                   sumcoef = MIN(weights[nvars - 1] + weights[nvars - 5], weights[nvars - 2] + weights[nvars - 3]);
9022                }
9023                else
9024                {
9025                   sumcoef = MIN(weights[nvars - 1] + weights[nvars - 4], weights[nvars - 1] + weights[nvars - 2] + weights[nvars - 3]);
9026                }
9027                break;
9028             default:
9029                return SCIP_ERROR;
9030             }
9031 
9032             /* tighten next coefficients that, pair with the current small coefficient, exceed the dualcapacity */
9033             minweight = weights[end];
9034             while( minweight <= sumcoef )
9035             {
9036                newweight = dualcapacity - minweight;
9037                startv = v;
9038                assert(v < nvars);
9039 
9040                /* @todo check for further reductions, when two times the minweight exceeds the dualcapacity */
9041                /* shrink big coefficients */
9042                while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9043                {
9044                   reductionsum += (weights[v] - newweight);
9045                   consdataChgWeight(consdata, v, newweight);
9046                   ++v;
9047                   assert(v < nvars);
9048                }
9049                (*nchgcoefs) += (v - startv);
9050 
9051                /* skip unchangable weights */
9052                while( weights[v] + minweight == dualcapacity )
9053                {
9054                   assert(v < nvars);
9055                   ++v;
9056                }
9057 
9058                --end;
9059                /* skip same end weights */
9060                while( end >= 0 && weights[end] == weights[end + 1] )
9061                   --end;
9062 
9063                if( v >= end )
9064                   goto TERMINATE;
9065 
9066                minweight = weights[end];
9067             }
9068 
9069             if( v >= end )
9070                goto TERMINATE;
9071 
9072             /* now check if a combination of small coefficients allows us to tighten big coefficients further */
9073             if( sumcoef < minweight )
9074             {
9075                minweight = sumcoef;
9076                newweight = dualcapacity - minweight;
9077                startv = v;
9078                assert(v < nvars);
9079 
9080                /* shrink big coefficients */
9081                while( weights[v] + minweight > dualcapacity && 2 * minweight <= dualcapacity )
9082                {
9083                   reductionsum += (weights[v] - newweight);
9084                   consdataChgWeight(consdata, v, newweight);
9085                   ++v;
9086                   assert(v < nvars);
9087                }
9088                (*nchgcoefs) += (v - startv);
9089 
9090                /* skip unchangable weights */
9091                while( weights[v] + minweight == dualcapacity )
9092                {
9093                   assert(v < nvars);
9094                   ++v;
9095                }
9096             }
9097 
9098             if( v >= end )
9099                goto TERMINATE;
9100 
9101             /* can we stop early, another special reduction case might exist */
9102             if( 2 * weights[end] > dualcapacity )
9103             {
9104                restsumweights = 0;
9105 
9106                /* determine capacity of the small items */
9107                for( w = end + 1; w < nvars; ++w )
9108                   restsumweights += weights[w];
9109 
9110                if( restsumweights * 2 <= dualcapacity )
9111                {
9112                   /* check for further posssible reductions in the middle */
9113                   while( v < end && restsumweights + weights[v] >= dualcapacity )
9114                      ++v;
9115 
9116                   if( v >= end )
9117                      goto TERMINATE;
9118 
9119                   /* dualcapacity is even, we can set the middle weights to dualcapacity/2 */
9120                   if( (dualcapacity & 1) == 0 )
9121                   {
9122                      newweight = dualcapacity / 2;
9123 
9124                      /* set all middle coefficients */
9125                      for( ; v <= end; ++v )
9126                      {
9127                         if( weights[v] > newweight )
9128                         {
9129                            reductionsum += (weights[v] - newweight);
9130                            consdataChgWeight(consdata, v, newweight);
9131                            ++(*nchgcoefs);
9132                         }
9133                      }
9134                   }
9135                   /* dualcapacity is odd, we can set the middle weights to dualcapacity but therefor need to multiply all
9136                    * other coefficients by 2
9137                    */
9138                   else
9139                   {
9140                      /* correct the reductionsum */
9141                      reductionsum *= 2;
9142 
9143                      /* multiply big coefficients by 2 */
9144                      for( w = 0; w < v; ++w )
9145                      {
9146                         consdataChgWeight(consdata, w, weights[w] * 2);
9147                      }
9148 
9149                      newweight = dualcapacity;
9150                      /* set all middle coefficients */
9151                      for( ; v <= end; ++v )
9152                      {
9153                         reductionsum += (2 * weights[v] - newweight);
9154                         consdataChgWeight(consdata, v, newweight);
9155                      }
9156 
9157                      /* multiply small coefficients by 2 */
9158                      for( w = end + 1; w < nvars; ++w )
9159                      {
9160                         consdataChgWeight(consdata, w, weights[w] * 2);
9161                      }
9162                      (*nchgcoefs) += nvars;
9163 
9164                      dualcapacity *= 2;
9165                      consdata->capacity *= 2;
9166                      ++(*nchgsides);
9167                   }
9168                }
9169 
9170                goto TERMINATE;
9171             }
9172 
9173             /* cannot tighten any further */
9174             if( 2 * sumcoef > dualcapacity )
9175                goto TERMINATE;
9176          }
9177       }
9178    }
9179 
9180  TERMINATE:
9181    /* correct capacity */
9182    if( reductionsum > 0 )
9183    {
9184       assert(v > 0);
9185 
9186       consdata->capacity -= reductionsum;
9187       ++(*nchgsides);
9188 
9189       assert(consdata->weightsum - dualcapacity == consdata->capacity);
9190    }
9191    assert(weights[0] <= consdata->capacity);
9192 
9193    /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal
9194     * weight must not be sorted by their index
9195     */
9196 #ifndef NDEBUG
9197    for( w = nvars - 1; w > 0; --w )
9198       assert(weights[w] <= weights[w - 1]);
9199 #endif
9200 
9201    if( oldnchgcoefs < *nchgcoefs )
9202    {
9203       assert(!SCIPconsIsDeleted(cons));
9204 
9205       /* it might be that we can divide the weights by their greatest common divisor */
9206       normalizeWeights(cons, nchgcoefs, nchgsides);
9207    }
9208    else
9209    {
9210       assert(oldnchgcoefs == *nchgcoefs);
9211       assert(oldnchgsides == *nchgsides);
9212    }
9213 
9214    return SCIP_OKAY;
9215 }
9216 
9217 
9218 /** fixes variables with weights bigger than the capacity and delete redundant constraints, also sort weights */
9219 static
prepareCons(SCIP * scip,SCIP_CONS * cons,int * nfixedvars,int * ndelconss,int * nchgcoefs)9220 SCIP_RETCODE prepareCons(
9221    SCIP*                 scip,               /**< SCIP data structure */
9222    SCIP_CONS*            cons,               /**< knapsack constraint */
9223    int*                  nfixedvars,         /**< pointer to store the amount of fixed variables */
9224    int*                  ndelconss,          /**< pointer to store the amount of deleted constraints */
9225    int*                  nchgcoefs           /**< pointer to store the amount of changed coefficients */
9226    )
9227 {
9228    SCIP_VAR** vars;
9229    SCIP_CONSDATA* consdata;
9230    SCIP_Longint* weights;
9231    SCIP_Longint capacity;
9232    SCIP_Bool infeasible;
9233    SCIP_Bool fixed;
9234    int nvars;
9235    int v;
9236 
9237    assert(scip != NULL);
9238    assert(cons != NULL);
9239    assert(nfixedvars != NULL);
9240    assert(ndelconss != NULL);
9241    assert(nchgcoefs != NULL);
9242 
9243    consdata = SCIPconsGetData(cons);
9244    assert(consdata != NULL);
9245 
9246    nvars = consdata->nvars;
9247 
9248    /* no variables left, then delete constraint */
9249    if( nvars == 0 )
9250    {
9251       assert(consdata->capacity >= 0);
9252 
9253       SCIP_CALL( SCIPdelCons(scip, cons) );
9254       ++(*ndelconss);
9255 
9256       return SCIP_OKAY;
9257    }
9258 
9259    /* sort items */
9260    sortItems(consdata);
9261 
9262    vars = consdata->vars;
9263    weights = consdata->weights;
9264    capacity = consdata->capacity;
9265    v = 0;
9266 
9267    /* check for weights bigger than the capacity */
9268    while( v < nvars && weights[v] > capacity )
9269    {
9270       SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
9271       assert(!infeasible);
9272 
9273       if( fixed )
9274          ++(*nfixedvars);
9275 
9276       ++v;
9277    }
9278 
9279    /* if we fixed at least one variable we need to delete them from the constraint */
9280    if( v > 0 )
9281    {
9282       if( v == nvars )
9283       {
9284          SCIP_CALL( SCIPdelCons(scip, cons) );
9285          ++(*ndelconss);
9286 
9287          return SCIP_OKAY;
9288       }
9289 
9290       /* delete all position from back to front */
9291       for( --v; v >= 0; --v )
9292       {
9293          SCIP_CALL( delCoefPos(scip, cons, v) );
9294          ++(*nchgcoefs);
9295       }
9296 
9297       /* sort items again because of deletion */
9298       sortItems(consdata);
9299       assert(vars == consdata->vars);
9300       assert(weights == consdata->weights);
9301    }
9302    assert(consdata->sorted);
9303    assert(weights[0] <= capacity);
9304 
9305    if( !SCIPisHugeValue(scip, (SCIP_Real) capacity) && consdata->weightsum <= capacity )
9306    {
9307       SCIP_CALL( SCIPdelCons(scip, cons) );
9308       ++(*ndelconss);
9309    }
9310 
9311    return SCIP_OKAY;
9312 }
9313 
9314 
9315 /** tries to simplify weights and delete redundant variables in knapsack a^Tx <= capacity
9316  *
9317  *  1. use the duality between a^Tx <= capacity   <=>   -a^T~x <= capacity - weightsum to tighten weights, e.g.
9318  *
9319  *     11x1 + 10x2 + 7x3 + 5x4 + 5x5 <= 25    <=>   -10~x1 - 10~x2 - 7~x3 - 5~x4 - 5~x5 <= -13
9320  *
9321  *     the above constraint can be changed to
9322  *
9323  *     -8~x1 - 8~x2 - 7~x3 - 5~x4 - 5~x5 <= -12   <=>   8x1 + 8x2 + 7x3 + 5x4 + 5x5 <= 20
9324  *
9325  *  2. if variables in a constraint do not affect the (in-)feasibility of the constraint, we can delete them, e.g.
9326  *
9327  *     7x1 + 6x2 + 5x3 + 5x4 + x5 + x6 <= 20 => x5 and x6 are redundant and can be removed
9328  *
9329  *  3. Tries to use gcd information an all but one weight to change this not-included weight and normalize the
9330  *     constraint further, e.g.
9331  *
9332  *     9x1 + 6x2 + 6x3 + 5x4 <= 13   =>   9x1 + 6x2 + 6x3 + 6x4 <= 12   =>   3x1 + 2x2 + 2x3 + 2x4 <= 4   =>   4x1 + 2x2 + 2x3 + 2x4 <= 4
9333  *                                                                                                        =>   2x1 + x2 + x3 + x4 <= 2
9334  *     9x1 + 6x2 + 6x3 + 7x4 <= 13   =>   9x1 + 6x2 + 6x3 + 6x4 <= 12   =>   see above
9335  */
9336 static
simplifyInequalities(SCIP * scip,SCIP_CONS * cons,int * nfixedvars,int * ndelconss,int * nchgcoefs,int * nchgsides,int * naddconss,SCIP_Bool * cutoff)9337 SCIP_RETCODE simplifyInequalities(
9338    SCIP*                 scip,               /**< SCIP data structure */
9339    SCIP_CONS*            cons,               /**< knapsack constraint */
9340    int*                  nfixedvars,         /**< pointer to store the amount of fixed variables */
9341    int*                  ndelconss,          /**< pointer to store the amount of deleted constraints */
9342    int*                  nchgcoefs,          /**< pointer to store the amount of changed coefficients */
9343    int*                  nchgsides,          /**< pointer to store the amount of changed sides */
9344    int*                  naddconss,          /**< pointer to count number of added constraints */
9345    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off */
9346    )
9347 {
9348    SCIP_VAR** vars;
9349    SCIP_CONSDATA* consdata;
9350    SCIP_Longint* weights;
9351    SCIP_Longint restweight;
9352    SCIP_Longint newweight;
9353    SCIP_Longint weight;
9354    SCIP_Longint oldgcd;
9355    SCIP_Longint rest;
9356    SCIP_Longint gcd;
9357    int oldnchgcoefs;
9358    int oldnchgsides;
9359    int candpos;
9360    int candpos2;
9361    int offsetv;
9362    int nvars;
9363    int v;
9364 
9365    assert(scip != NULL);
9366    assert(cons != NULL);
9367    assert(nfixedvars != NULL);
9368    assert(ndelconss != NULL);
9369    assert(nchgcoefs != NULL);
9370    assert(nchgsides != NULL);
9371    assert(naddconss != NULL);
9372    assert(cutoff != NULL);
9373    assert(!SCIPconsIsModifiable(cons));
9374 
9375    consdata = SCIPconsGetData(cons);
9376    assert( consdata != NULL );
9377 
9378    *cutoff = FALSE;
9379 
9380    /* remove double enties and also combinations of active and negated variables */
9381    SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
9382    assert(consdata->merged);
9383    if( *cutoff )
9384       return SCIP_OKAY;
9385 
9386    assert(consdata->capacity >= 0);
9387 
9388    /* fix variables with big coefficients and remove redundant constraints, sort weights */
9389    SCIP_CALL( prepareCons(scip, cons, nfixedvars, ndelconss, nchgcoefs) );
9390 
9391    if( SCIPconsIsDeleted(cons) )
9392       return SCIP_OKAY;
9393 
9394    if( !SCIPisHugeValue(scip, (SCIP_Real) consdata->capacity) )
9395    {
9396       /* 1. dual weights tightening */
9397       SCIP_CALL( dualWeightsTightening(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9398 
9399       if( SCIPconsIsDeleted(cons) )
9400          return SCIP_OKAY;
9401       /* 2. delete redundant variables */
9402       SCIP_CALL( detectRedundantVars(scip, cons, ndelconss, nchgcoefs, nchgsides, naddconss) );
9403 
9404       if( SCIPconsIsDeleted(cons) )
9405          return SCIP_OKAY;
9406    }
9407 
9408    weights = consdata->weights;
9409    nvars = consdata->nvars;
9410 
9411 #ifndef NDEBUG
9412    /* constraint might not be sorted, but the weights are already sorted */
9413    for( v = nvars - 1; v > 0; --v )
9414       assert(weights[v] <= weights[v-1]);
9415 #endif
9416 
9417    /* determine greatest common divisor */
9418    gcd = weights[nvars - 1];
9419    for( v = nvars - 2; v >= 0 && gcd > 1; --v )
9420    {
9421       gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9422    }
9423 
9424    /* divide the constraint by their greatest common divisor */
9425    if( gcd >= 2 )
9426    {
9427       for( v = nvars - 1; v >= 0; --v )
9428       {
9429          consdataChgWeight(consdata, v, weights[v]/gcd);
9430       }
9431       (*nchgcoefs) += nvars;
9432 
9433       consdata->capacity /= gcd;
9434       (*nchgsides)++;
9435    }
9436    assert(consdata->nvars == nvars);
9437 
9438    /* weight should still be sorted, because the reduction preserves this, but corresponding variables with equal weight
9439     * must not be sorted by their index
9440     */
9441 #ifndef NDEBUG
9442    for( v = nvars - 1; v > 0; --v )
9443       assert(weights[v] <= weights[v-1]);
9444 #endif
9445 
9446    /* 3. start gcd procedure for all variables */
9447    do
9448    {
9449       SCIPdebug( oldnchgcoefs = *nchgcoefs; )
9450       SCIPdebug( oldnchgsides = *nchgsides; )
9451 
9452       vars = consdata->vars;
9453       weights = consdata->weights;
9454       nvars = consdata->nvars;
9455 
9456       /* stop if we have two coefficients which are one in absolute value */
9457       if( weights[nvars - 1] == 1 && weights[nvars - 2] == 1 )
9458          return SCIP_OKAY;
9459 
9460       v = 0;
9461       /* determine coefficients as big as the capacity, these we do not need to take into account when calculating the
9462        * gcd
9463        */
9464       while( weights[v] == consdata->capacity )
9465       {
9466          ++v;
9467          assert(v < nvars);
9468       }
9469 
9470       /* all but one variable are as big as the capacity, this is handled elsewhere */
9471       if( v == nvars - 1 )
9472          return SCIP_OKAY;
9473 
9474       offsetv = v;
9475 
9476       gcd = -1;
9477       candpos = -1;
9478       candpos2 = -1;
9479 
9480       /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
9481        * change the coefficient
9482        */
9483       for( v = nvars - 1; v >= offsetv; --v )
9484       {
9485          weight = weights[v];
9486          assert(weight >= 1);
9487 
9488          oldgcd = gcd;
9489 
9490          if( gcd == -1 )
9491          {
9492             gcd = weights[v];
9493             assert(gcd >= 1);
9494          }
9495          else
9496          {
9497             /* calculate greatest common divisor for all variables */
9498             gcd = SCIPcalcGreComDiv(gcd, weight);
9499          }
9500 
9501          /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
9502           * can terminate
9503           */
9504          if( gcd == 1 )
9505          {
9506             /* found candidate */
9507             if( candpos == -1 )
9508             {
9509                gcd = oldgcd;
9510                candpos = v;
9511 
9512                /* if both first coefficients have a gcd of 1, both are candidates for the coefficient change */
9513                if( v == nvars - 2 )
9514                   candpos2 = v + 1;
9515             }
9516             /* two different variables lead to a gcd of one, so we cannot change a coefficient */
9517             else
9518             {
9519                if( candpos == v + 1 && candpos2 == v + 2 )
9520                {
9521                   assert(candpos2 == nvars - 1);
9522 
9523                   /* take new candidates */
9524                   candpos = candpos2;
9525 
9526                   /* recalculate gcd from scratch */
9527                   gcd = weights[v+1];
9528                   assert(gcd >= 1);
9529 
9530                   /* calculate greatest common divisor for variables */
9531                   gcd = SCIPcalcGreComDiv(gcd, weights[v]);
9532                   if( gcd == 1 )
9533                      return SCIP_OKAY;
9534                }
9535                else
9536                   /* cannot determine a possible coefficient for reduction */
9537                   return SCIP_OKAY;
9538             }
9539          }
9540       }
9541       assert(gcd >= 2);
9542 
9543       /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
9544        * further
9545        */
9546       assert(((candpos >= offsetv) || (candpos == -1 && offsetv > 0)) && candpos < nvars);
9547 
9548       /* determine the remainder of the capacity and the gcd */
9549       rest = consdata->capacity % gcd;
9550       assert(rest >= 0);
9551       assert(rest < gcd);
9552 
9553       if( candpos == -1 )
9554       {
9555          /* we assume that the constraint was normalized */
9556          assert(rest > 0);
9557 
9558          /* replace old with new capacity */
9559          consdata->capacity -= rest;
9560          ++(*nchgsides);
9561 
9562          /* replace old big coefficients with new capacity */
9563          for( v = 0; v < offsetv; ++v )
9564          {
9565             consdataChgWeight(consdata, v, consdata->capacity);
9566          }
9567 
9568          *nchgcoefs += offsetv;
9569          goto CONTINUE;
9570       }
9571 
9572       /* determine the remainder of the coefficient candidate and the gcd */
9573       restweight = weights[candpos] % gcd;
9574       assert(restweight >= 1);
9575       assert(restweight < gcd);
9576 
9577       /* calculate new coefficient */
9578       if( restweight > rest )
9579          newweight = weights[candpos] - restweight + gcd;
9580       else
9581          newweight = weights[candpos] - restweight;
9582 
9583       assert(newweight == 0 || SCIPcalcGreComDiv(gcd, newweight) == gcd);
9584 
9585       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);
9586 
9587       /* must not change weights and capacity if one variable would be removed and we have a big coefficient,
9588        * e.g., 11x1 + 6x2 + 6x3 + 5x4 <= 11 => gcd = 6, offsetv = 1 => newweight = 0, but we would lose x1 = 1 => x4 = 0
9589        */
9590       if( newweight == 0 && offsetv > 0 )
9591          return SCIP_OKAY;
9592 
9593       if( rest > 0 )
9594       {
9595          /* replace old with new capacity */
9596          consdata->capacity -= rest;
9597          ++(*nchgsides);
9598 
9599          /* replace old big coefficients with new capacity */
9600          for( v = 0; v < offsetv; ++v )
9601          {
9602             consdataChgWeight(consdata, v, consdata->capacity);
9603          }
9604 
9605          *nchgcoefs += offsetv;
9606       }
9607 
9608       if( newweight == 0 )
9609       {
9610          /* delete redundant coefficient */
9611          SCIP_CALL( delCoefPos(scip, cons, candpos) );
9612          assert(consdata->nvars == nvars - 1);
9613          --nvars;
9614       }
9615       else
9616       {
9617          /* replace old with new coefficient */
9618          consdataChgWeight(consdata, candpos, newweight);
9619       }
9620       ++(*nchgcoefs);
9621 
9622       assert(consdata->vars == vars);
9623       assert(consdata->nvars == nvars);
9624       assert(consdata->weights == weights);
9625 
9626    CONTINUE:
9627       /* now constraint can be normalized, dividing it by the gcd */
9628       for( v = nvars - 1; v >= 0; --v )
9629       {
9630          consdataChgWeight(consdata, v, weights[v]/gcd);
9631       }
9632       (*nchgcoefs) += nvars;
9633 
9634       consdata->capacity /= gcd;
9635       ++(*nchgsides);
9636 
9637       SCIPdebugPrintCons(scip, cons, NULL);
9638 
9639       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));
9640    }
9641    while( nvars >= 2 );
9642 
9643    return SCIP_OKAY;
9644 }
9645 
9646 
9647 /** inserts an element into the list of binary zero implications */
9648 static
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)9649 SCIP_RETCODE insertZerolist(
9650    SCIP*                 scip,               /**< SCIP data structure */
9651    int**                 liftcands,          /**< array of the lifting candidates */
9652    int*                  nliftcands,         /**< number of lifting candidates */
9653    int**                 firstidxs,          /**< array of first zeroitems indices */
9654    SCIP_Longint**        zeroweightsums,     /**< array of sums of weights of the implied-to-zero items */
9655    int**                 zeroitems,          /**< pointer to zero items array */
9656    int**                 nextidxs,           /**< pointer to array of next zeroitems indeces */
9657    int*                  zeroitemssize,      /**< pointer to size of zero items array */
9658    int*                  nzeroitems,         /**< pointer to length of zero items array */
9659    int                   probindex,          /**< problem index of variable y in implication y == v -> x == 0 */
9660    SCIP_Bool             value,              /**< value v of variable y in implication */
9661    int                   knapsackidx,        /**< index of variable x in knapsack */
9662    SCIP_Longint          knapsackweight,     /**< weight of variable x in knapsack */
9663    SCIP_Bool*            memlimitreached     /**< pointer to store whether the memory limit was reached */
9664    )
9665 {
9666    int nzeros;
9667 
9668    assert(liftcands != NULL);
9669    assert(liftcands[value] != NULL);
9670    assert(nliftcands != NULL);
9671    assert(firstidxs != NULL);
9672    assert(firstidxs[value] != NULL);
9673    assert(zeroweightsums != NULL);
9674    assert(zeroweightsums[value] != NULL);
9675    assert(zeroitems != NULL);
9676    assert(nextidxs != NULL);
9677    assert(zeroitemssize != NULL);
9678    assert(nzeroitems != NULL);
9679    assert(*nzeroitems <= *zeroitemssize);
9680    assert(0 <= probindex && probindex < SCIPgetNVars(scip) - SCIPgetNContVars(scip));
9681    assert(memlimitreached != NULL);
9682 
9683    nzeros = *nzeroitems;
9684 
9685    /* allocate enough memory */
9686    if( nzeros == *zeroitemssize )
9687    {
9688       /* we explicitly construct the complete implication graph where the knapsack variables are involved;
9689        * this can be too huge - abort on memory limit
9690        */
9691       if( *zeroitemssize >= MAX_ZEROITEMS_SIZE )
9692       {
9693          SCIPdebugMsg(scip, "memory limit of %d bytes reached in knapsack preprocessing - abort collecting zero items\n",
9694             *zeroitemssize);
9695          *memlimitreached = TRUE;
9696          return SCIP_OKAY;
9697       }
9698       *zeroitemssize *= 2;
9699       *zeroitemssize = MIN(*zeroitemssize, MAX_ZEROITEMS_SIZE);
9700       SCIP_CALL( SCIPreallocBufferArray(scip, zeroitems, *zeroitemssize) );
9701       SCIP_CALL( SCIPreallocBufferArray(scip, nextidxs, *zeroitemssize) );
9702    }
9703    assert(nzeros < *zeroitemssize);
9704 
9705    if( *memlimitreached )
9706       *memlimitreached = FALSE;
9707 
9708    /* insert element */
9709    (*zeroitems)[nzeros] = knapsackidx;
9710    (*nextidxs)[nzeros] = firstidxs[value][probindex];
9711    if( firstidxs[value][probindex] == 0 )
9712    {
9713       liftcands[value][nliftcands[value]] = probindex;
9714       ++nliftcands[value];
9715    }
9716    firstidxs[value][probindex] = nzeros;
9717    ++(*nzeroitems);
9718    zeroweightsums[value][probindex] += knapsackweight;
9719 
9720    return SCIP_OKAY;
9721 }
9722 
9723 #define MAX_CLIQUELENGTH 50
9724 /** applies rule (3) of the weight tightening procedure, which can lift other variables into the knapsack:
9725  *  (3) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
9726  *      let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
9727  *      if cliqueweightsum(xi == v) < capacity:
9728  *      - fixing variable xi to v would make the knapsack constraint redundant
9729  *      - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
9730  *        redundancy effect:
9731  *          wi'       := capacity - cliqueweightsum(xi == v)
9732  *      this rule can also be applied to binary variables not in the knapsack!
9733  */
9734 static
tightenWeightsLift(SCIP * scip,SCIP_CONS * cons,int * nchgcoefs,SCIP_Bool * cutoff)9735 SCIP_RETCODE tightenWeightsLift(
9736    SCIP*                 scip,               /**< SCIP data structure */
9737    SCIP_CONS*            cons,               /**< knapsack constraint */
9738    int*                  nchgcoefs,          /**< pointer to count total number of changed coefficients */
9739    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off */
9740    )
9741 {
9742    SCIP_CONSDATA* consdata;
9743    SCIP_VAR** binvars;
9744    int nbinvars;
9745    int* liftcands[2];          /* binary variables that have at least one entry in zeroitems */
9746    int* firstidxs[2];          /* first index in zeroitems for each binary variable/value pair, or zero for empty list */
9747    SCIP_Longint* zeroweightsums[2]; /* sums of weights of the implied-to-zero items */
9748    int* zeroitems;             /* item number in knapsack that is implied to zero */
9749    int* nextidxs;              /* next index in zeroitems for the same binary variable, or zero for end of list */
9750    int zeroitemssize;
9751    int nzeroitems;
9752    SCIP_Bool* zeroiteminserted[2];
9753    SCIP_Bool memlimitreached;
9754    int nliftcands[2];
9755    SCIP_Bool* cliqueused;
9756    SCIP_Bool* itemremoved;
9757    SCIP_Longint maxcliqueweightsum;
9758    SCIP_VAR** addvars;
9759    SCIP_Longint* addweights;
9760    SCIP_Longint addweightsum;
9761    int nvars;
9762    int cliquenum;
9763    int naddvars;
9764    int val;
9765    int i;
9766 
9767    int* tmpindices;
9768    SCIP_Bool* tmpboolindices;
9769    int* tmpindices2;
9770    SCIP_Bool* tmpboolindices2;
9771    int* tmpindices3;
9772    SCIP_Bool* tmpboolindices3;
9773    int tmp;
9774    int tmp2;
9775    int tmp3;
9776    SCIP_CONSHDLR* conshdlr;
9777    SCIP_CONSHDLRDATA* conshdlrdata;
9778 
9779    assert(nchgcoefs != NULL);
9780    assert(!SCIPconsIsModifiable(cons));
9781 
9782    consdata = SCIPconsGetData(cons);
9783    assert(consdata != NULL);
9784    assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
9785    assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
9786    assert(consdata->nvars > 0);
9787    assert(consdata->merged);
9788 
9789    nvars = consdata->nvars;
9790 
9791    /* check if the knapsack has too many items/cliques for applying this costly method */
9792    if( (!consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE) || consdata->ncliques > MAX_USECLIQUES_SIZE )
9793       return SCIP_OKAY;
9794 
9795    /* sort items, s.t. the heaviest one is in the first position */
9796    sortItems(consdata);
9797 
9798    if( !consdata->cliquepartitioned && nvars > MAX_USECLIQUES_SIZE )
9799       return SCIP_OKAY;
9800 
9801    /* we have to consider all integral variables since even integer and implicit integer variables can have binary bounds */
9802    nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
9803    assert(nbinvars > 0);
9804    binvars = SCIPgetVars(scip);
9805 
9806    /* get conshdlrdata to use cleared memory */
9807    conshdlr = SCIPconsGetHdlr(cons);
9808    assert(conshdlr != NULL);
9809    conshdlrdata = SCIPconshdlrGetData(conshdlr);
9810    assert(conshdlrdata != NULL);
9811 
9812    /* allocate temporary memory for the list of implied to zero variables */
9813    zeroitemssize = MIN(nbinvars, MAX_ZEROITEMS_SIZE); /* initial size of zeroitems buffer */
9814    SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[0], nbinvars) );
9815    SCIP_CALL( SCIPallocBufferArray(scip, &liftcands[1], nbinvars) );
9816 
9817    assert(conshdlrdata->ints1size > 0);
9818    assert(conshdlrdata->ints2size > 0);
9819    assert(conshdlrdata->longints1size > 0);
9820    assert(conshdlrdata->longints2size > 0);
9821 
9822    /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9823     * than binary + integer variables existed at the presolving initialization method, but for example if you would
9824     * transform all integers into their binary representation then it maybe happens
9825     */
9826    if( conshdlrdata->ints1size < nbinvars )
9827    {
9828       int oldsize = conshdlrdata->ints1size;
9829 
9830       conshdlrdata->ints1size = nbinvars;
9831       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints1, oldsize, conshdlrdata->ints1size) );
9832       BMSclearMemoryArray(&(conshdlrdata->ints1[oldsize]), conshdlrdata->ints1size - oldsize); /*lint !e866*/
9833    }
9834    if( conshdlrdata->ints2size < nbinvars )
9835    {
9836       int oldsize = conshdlrdata->ints2size;
9837 
9838       conshdlrdata->ints2size = nbinvars;
9839       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->ints2, oldsize, conshdlrdata->ints2size) );
9840       BMSclearMemoryArray(&(conshdlrdata->ints2[oldsize]), conshdlrdata->ints2size - oldsize); /*lint !e866*/
9841    }
9842    if( conshdlrdata->longints1size < nbinvars )
9843    {
9844       int oldsize = conshdlrdata->longints1size;
9845 
9846       conshdlrdata->longints1size = nbinvars;
9847       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints1, oldsize, conshdlrdata->longints1size) );
9848       BMSclearMemoryArray(&(conshdlrdata->longints1[oldsize]), conshdlrdata->longints1size - oldsize); /*lint !e866*/
9849    }
9850    if( conshdlrdata->longints2size < nbinvars )
9851    {
9852       int oldsize = conshdlrdata->longints2size;
9853 
9854       conshdlrdata->longints2size = nbinvars;
9855       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->longints2, oldsize, conshdlrdata->longints2size) );
9856       BMSclearMemoryArray(&(conshdlrdata->longints2[oldsize]), conshdlrdata->longints2size - oldsize); /*lint !e866*/
9857    }
9858 
9859    firstidxs[0] = conshdlrdata->ints1;
9860    firstidxs[1] = conshdlrdata->ints2;
9861    zeroweightsums[0] = conshdlrdata->longints1;
9862    zeroweightsums[1] = conshdlrdata->longints2;
9863 
9864    /* check for cleared arrays, all entries are zero */
9865 #ifndef NDEBUG
9866    for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9867    {
9868       assert(firstidxs[0][tmp] == 0);
9869       assert(firstidxs[1][tmp] == 0);
9870       assert(zeroweightsums[0][tmp] == 0);
9871       assert(zeroweightsums[1][tmp] == 0);
9872    }
9873 #endif
9874 
9875    SCIP_CALL( SCIPallocBufferArray(scip, &zeroitems, zeroitemssize) );
9876    SCIP_CALL( SCIPallocBufferArray(scip, &nextidxs, zeroitemssize) );
9877 
9878    zeroitems[0] = -1; /* dummy element */
9879    nextidxs[0] = -1;
9880    nzeroitems = 1;
9881    nliftcands[0] = 0;
9882    nliftcands[1] = 0;
9883 
9884    assert(conshdlrdata->bools1size > 0);
9885    assert(conshdlrdata->bools2size > 0);
9886 
9887    /* next if conditions should normally not be true, because it means that presolving has created more binary variables
9888     * than binary + integer variables existed at the presolving initialization method, but for example if you would
9889     * transform all integers into their binary representation then it maybe happens
9890     */
9891    if( conshdlrdata->bools1size < nbinvars )
9892    {
9893       int oldsize = conshdlrdata->bools1size;
9894 
9895       conshdlrdata->bools1size = nbinvars;
9896       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools1, oldsize, conshdlrdata->bools1size) );
9897       BMSclearMemoryArray(&(conshdlrdata->bools1[oldsize]), conshdlrdata->bools1size - oldsize); /*lint !e866*/
9898    }
9899    if( conshdlrdata->bools2size < nbinvars )
9900    {
9901       int oldsize = conshdlrdata->bools2size;
9902 
9903       conshdlrdata->bools2size = nbinvars;
9904       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools2, oldsize, conshdlrdata->bools2size) );
9905       BMSclearMemoryArray(&(conshdlrdata->bools2[oldsize]), conshdlrdata->bools2size - oldsize); /*lint !e866*/
9906    }
9907 
9908    zeroiteminserted[0] = conshdlrdata->bools1;
9909    zeroiteminserted[1] = conshdlrdata->bools2;
9910 
9911    /* check for cleared arrays, all entries are zero */
9912 #ifndef NDEBUG
9913    for( tmp = nbinvars - 1; tmp >= 0; --tmp )
9914    {
9915       assert(zeroiteminserted[0][tmp] == 0);
9916       assert(zeroiteminserted[1][tmp] == 0);
9917    }
9918 #endif
9919 
9920    SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices3, consdata->nvars) );
9921    SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices2, 2 * nbinvars) );
9922    SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices3, consdata->nvars) );
9923    SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices2, 2 * nbinvars) );
9924    SCIP_CALL( SCIPallocBufferArray(scip, &tmpindices, 2 * nbinvars) );
9925    SCIP_CALL( SCIPallocBufferArray(scip, &tmpboolindices, 2 * nbinvars) );
9926 
9927    tmp2 = 0;
9928    tmp3 = 0;
9929 
9930    memlimitreached = FALSE;
9931    for( i = 0; i < consdata->nvars && !memlimitreached; ++i )
9932    {
9933       SCIP_CLIQUE** cliques;
9934       SCIP_VAR* var;
9935       SCIP_Longint weight;
9936       SCIP_Bool value;
9937       int varprobindex;
9938       int ncliques;
9939       int j;
9940 
9941       tmp = 0;
9942 
9943       /* get corresponding active problem variable */
9944       var = consdata->vars[i];
9945       weight = consdata->weights[i];
9946       value = TRUE;
9947       SCIP_CALL( SCIPvarGetProbvarBinary(&var, &value) );
9948       varprobindex = SCIPvarGetProbindex(var);
9949       assert(0 <= varprobindex && varprobindex < nbinvars);
9950 
9951       /* update the zeroweightsum */
9952       zeroweightsums[!value][varprobindex] += weight; /*lint !e514*/
9953       tmpboolindices3[tmp3] = !value;
9954       tmpindices3[tmp3] = varprobindex;
9955       ++tmp3;
9956 
9957       /* initialize the arrays of inserted zero items */
9958       /* first add the implications (~x == 1 -> x == 0) */
9959       {
9960          SCIP_Bool implvalue;
9961          int probindex;
9962 
9963          probindex = SCIPvarGetProbindex(var);
9964          assert(0 <= probindex && probindex < nbinvars);
9965 
9966          implvalue = !value;
9967 
9968          /* insert the item into the list of the implied variable/value */
9969          assert( !zeroiteminserted[implvalue][probindex] );
9970 
9971          if( firstidxs[implvalue][probindex] == 0 )
9972          {
9973             tmpboolindices2[tmp2] = implvalue;
9974             tmpindices2[tmp2] = probindex;
9975             ++tmp2;
9976          }
9977          SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
9978                &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
9979                &memlimitreached) );
9980          zeroiteminserted[implvalue][probindex] = TRUE;
9981          tmpboolindices[tmp] = implvalue;
9982          tmpindices[tmp] = probindex;
9983          ++tmp;
9984       }
9985 
9986       /* get the cliques where the knapsack item is member of with value 1 */
9987       ncliques = SCIPvarGetNCliques(var, value);
9988       cliques = SCIPvarGetCliques(var, value);
9989       for( j = 0; j < ncliques && !memlimitreached; ++j )
9990       {
9991          SCIP_VAR** cliquevars;
9992          SCIP_Bool* cliquevalues;
9993          int ncliquevars;
9994          int k;
9995 
9996          ncliquevars = SCIPcliqueGetNVars(cliques[j]);
9997 
9998          /* discard big cliques */
9999          if( ncliquevars > MAX_CLIQUELENGTH )
10000             continue;
10001 
10002          cliquevars = SCIPcliqueGetVars(cliques[j]);
10003          cliquevalues = SCIPcliqueGetValues(cliques[j]);
10004 
10005          for( k = ncliquevars - 1; k >= 0; --k )
10006          {
10007             SCIP_Bool implvalue;
10008             int probindex;
10009 
10010             if( var == cliquevars[k] )
10011                continue;
10012 
10013             probindex = SCIPvarGetProbindex(cliquevars[k]);
10014             if( probindex == -1 )
10015                continue;
10016 
10017             assert(0 <= probindex && probindex < nbinvars);
10018             implvalue = cliquevalues[k];
10019 
10020             /* insert the item into the list of the clique variable/value */
10021             if( !zeroiteminserted[implvalue][probindex] )
10022             {
10023                if( firstidxs[implvalue][probindex] == 0 )
10024                {
10025                   tmpboolindices2[tmp2] = implvalue;
10026                   tmpindices2[tmp2] = probindex;
10027                   ++tmp2;
10028                }
10029 
10030                SCIP_CALL( insertZerolist(scip, liftcands, nliftcands, firstidxs, zeroweightsums,
10031                      &zeroitems, &nextidxs, &zeroitemssize, &nzeroitems, probindex, implvalue, i, weight,
10032                      &memlimitreached) );
10033                zeroiteminserted[implvalue][probindex] = TRUE;
10034                tmpboolindices[tmp] = implvalue;
10035                tmpindices[tmp] = probindex;
10036                ++tmp;
10037 
10038                if( memlimitreached )
10039                   break;
10040             }
10041          }
10042       }
10043       /* clear zeroiteminserted */
10044       for( --tmp; tmp >= 0; --tmp)
10045          zeroiteminserted[tmpboolindices[tmp]][tmpindices[tmp]] = FALSE;
10046    }
10047    SCIPfreeBufferArray(scip, &tmpboolindices);
10048 
10049    /* calculate the clique partition and the maximal sum of weights using the clique information */
10050    assert(consdata->sorted);
10051    SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10052 
10053    assert(conshdlrdata->bools3size > 0);
10054 
10055    /* next if condition should normally not be true, because it means that presolving has created more binary variables
10056     * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10057     * method, but for example if you would transform all integers into their binary representation then it maybe happens
10058     */
10059    if( conshdlrdata->bools3size < consdata->nvars )
10060    {
10061       int oldsize = conshdlrdata->bools3size;
10062 
10063       conshdlrdata->bools3size = consdata->nvars;;
10064       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools3, oldsize, conshdlrdata->bools3size) );
10065       BMSclearMemoryArray(&(conshdlrdata->bools3[oldsize]), conshdlrdata->bools3size - oldsize); /*lint !e866*/
10066    }
10067 
10068    cliqueused = conshdlrdata->bools3;
10069 
10070    /* check for cleared array, all entries are zero */
10071 #ifndef NDEBUG
10072    for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10073       assert(cliqueused[tmp] == 0);
10074 #endif
10075 
10076    maxcliqueweightsum = 0;
10077    tmp = 0;
10078 
10079    /* calculates maximal weight of cliques */
10080    for( i = 0; i < consdata->nvars; ++i )
10081    {
10082       cliquenum = consdata->cliquepartition[i];
10083       assert(0 <= cliquenum && cliquenum < consdata->nvars);
10084 
10085       if( !cliqueused[cliquenum] )
10086       {
10087          maxcliqueweightsum += consdata->weights[i];
10088          cliqueused[cliquenum] = TRUE;
10089          tmpindices[tmp] = cliquenum;
10090          ++tmp;
10091       }
10092    }
10093    /* clear cliqueused */
10094    for( --tmp; tmp >= 0; --tmp)
10095       cliqueused[tmp] = FALSE;
10096 
10097    assert(conshdlrdata->bools4size > 0);
10098 
10099    /* next if condition should normally not be true, because it means that presolving has created more binary variables
10100     * in one constraint than binary + integer variables existed in the whole problem at the presolving initialization
10101     * method, but for example if you would transform all integers into their binary representation then it maybe happens
10102     */
10103    if( conshdlrdata->bools4size < consdata->nvars )
10104    {
10105       int oldsize = conshdlrdata->bools4size;
10106 
10107       conshdlrdata->bools4size = consdata->nvars;
10108       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->bools4, oldsize, conshdlrdata->bools4size) );
10109       BMSclearMemoryArray(&conshdlrdata->bools4[oldsize], conshdlrdata->bools4size - oldsize); /*lint !e866*/
10110    }
10111 
10112    itemremoved = conshdlrdata->bools4;
10113 
10114    /* check for cleared array, all entries are zero */
10115 #ifndef NDEBUG
10116    for( tmp = consdata->nvars - 1; tmp >= 0; --tmp )
10117       assert(itemremoved[tmp] == 0);
10118 #endif
10119 
10120    /* for each binary variable xi and each fixing v, calculate the cliqueweightsum and update the weight of the
10121     * variable in the knapsack (this is sequence-dependent because the new or modified weights have to be
10122     * included in subsequent cliqueweightsum calculations)
10123     */
10124    SCIP_CALL( SCIPallocBufferArray(scip, &addvars, 2*nbinvars) );
10125    SCIP_CALL( SCIPallocBufferArray(scip, &addweights, 2*nbinvars) );
10126    naddvars = 0;
10127    addweightsum = 0;
10128    for( val = 0; val < 2 && addweightsum < consdata->capacity; ++val )
10129    {
10130       for( i = 0; i < nliftcands[val] && addweightsum < consdata->capacity; ++i )
10131       {
10132          SCIP_Longint cliqueweightsum;
10133          int probindex;
10134          int idx;
10135          int j;
10136 
10137          tmp = 0;
10138 
10139          probindex = liftcands[val][i];
10140          assert(0 <= probindex && probindex < nbinvars);
10141 
10142          /* ignore empty zero lists and variables that cannot be lifted anyways */
10143          if( firstidxs[val][probindex] == 0
10144             || maxcliqueweightsum - zeroweightsums[val][probindex] + addweightsum >= consdata->capacity )
10145             continue;
10146 
10147          /* mark the items that are implied to zero by setting the current variable to the current value */
10148          for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10149          {
10150             assert(0 < idx && idx < nzeroitems);
10151             assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10152             itemremoved[zeroitems[idx]] = TRUE;
10153          }
10154 
10155          /* calculate the residual cliqueweight sum */
10156          cliqueweightsum = addweightsum; /* the previously added items are single-element cliques */
10157          for( j = 0; j < consdata->nvars; ++j )
10158          {
10159             cliquenum = consdata->cliquepartition[j];
10160             assert(0 <= cliquenum && cliquenum < consdata->nvars);
10161             if( !itemremoved[j] )
10162             {
10163                if( !cliqueused[cliquenum] )
10164                {
10165                   cliqueweightsum += consdata->weights[j];
10166                   cliqueused[cliquenum] = TRUE;
10167                   tmpindices[tmp] = cliquenum;
10168                   ++tmp;
10169                }
10170 
10171                if( cliqueweightsum >= consdata->capacity )
10172                   break;
10173             }
10174          }
10175 
10176          /* check if the weight of the variable/value can be increased */
10177          if( cliqueweightsum < consdata->capacity )
10178          {
10179             SCIP_VAR* var;
10180             SCIP_Longint weight;
10181 
10182             /* insert the variable (with value TRUE) in the list of additional items */
10183             assert(naddvars < 2*nbinvars);
10184             var = binvars[probindex];
10185             if( val == FALSE )
10186             {
10187                SCIP_CALL( SCIPgetNegatedVar(scip, var, &var) );
10188             }
10189             weight = consdata->capacity - cliqueweightsum;
10190             addvars[naddvars] = var;
10191             addweights[naddvars] = weight;
10192             addweightsum += weight;
10193             naddvars++;
10194 
10195             SCIPdebugMsg(scip, "knapsack constraint <%s>: adding lifted item %" SCIP_LONGINT_FORMAT "<%s>\n",
10196                SCIPconsGetName(cons), weight, SCIPvarGetName(var));
10197          }
10198 
10199          /* clear itemremoved */
10200          for( idx = firstidxs[val][probindex]; idx != 0; idx = nextidxs[idx] )
10201          {
10202             assert(0 < idx && idx < nzeroitems);
10203             assert(0 <= zeroitems[idx] && zeroitems[idx] < consdata->nvars);
10204             itemremoved[zeroitems[idx]] = FALSE;
10205          }
10206          /* clear cliqueused */
10207          for( --tmp; tmp >= 0; --tmp)
10208             cliqueused[tmpindices[tmp]] = FALSE;
10209       }
10210    }
10211 
10212    /* clear part of zeroweightsums */
10213    for( --tmp3; tmp3 >= 0; --tmp3)
10214       zeroweightsums[tmpboolindices3[tmp3]][tmpindices3[tmp3]] = 0;
10215 
10216    /* clear rest of zeroweightsums and firstidxs */
10217    for( --tmp2; tmp2 >= 0; --tmp2)
10218    {
10219       zeroweightsums[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10220       firstidxs[tmpboolindices2[tmp2]][tmpindices2[tmp2]] = 0;
10221    }
10222 
10223    /* add all additional item weights */
10224    for( i = 0; i < naddvars; ++i )
10225    {
10226       SCIP_CALL( addCoef(scip, cons, addvars[i], addweights[i]) );
10227    }
10228    *nchgcoefs += naddvars;
10229 
10230    if( naddvars > 0 )
10231    {
10232       /* if new items were added, multiple entries of the same variable are possible and we have to clean up the constraint */
10233       SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10234    }
10235 
10236    /* free temporary memory */
10237    SCIPfreeBufferArray(scip, &addweights);
10238    SCIPfreeBufferArray(scip, &addvars);
10239    SCIPfreeBufferArray(scip, &tmpindices);
10240    SCIPfreeBufferArray(scip, &tmpindices2);
10241    SCIPfreeBufferArray(scip, &tmpindices3);
10242    SCIPfreeBufferArray(scip, &tmpboolindices2);
10243    SCIPfreeBufferArray(scip, &tmpboolindices3);
10244    SCIPfreeBufferArray(scip, &nextidxs);
10245    SCIPfreeBufferArray(scip, &zeroitems);
10246    SCIPfreeBufferArray(scip, &liftcands[1]);
10247    SCIPfreeBufferArray(scip, &liftcands[0]);
10248 
10249    return SCIP_OKAY;
10250 }
10251 
10252 /** tightens item weights and capacity in presolving:
10253  *  given a knapsack sum(wi*xi) <= capacity
10254  *  (1) let weightsum := sum(wi)
10255  *      if weightsum - wi < capacity:
10256  *      - not using item i would make the knapsack constraint redundant
10257  *      - wi and capacity can be changed to have the same redundancy effect and the same results for
10258  *        fixing xi to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10259  *      - change coefficients:
10260  *          wi'       := weightsum - capacity
10261  *          capacity' := capacity - (wi - wi')
10262  *  (2) increase weights from front to back(sortation is necessary) if there is no space left for another weight
10263  *      - determine the four(can be adjusted) minimal weightsums of the knapsack, i.e. in increasing order
10264  *        weights[nvars - 1], weights[nvars - 2], MIN(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]),
10265  *        MIN(MAX(weights[nvars - 3], weights[nvars - 1] + weights[nvars - 2]), weights[nvars - 4]), note that there
10266  *        can be multiple times the same weight, this can be improved
10267  *      - check if summing up a minimal weightsum with a big weight exceeds the capacity, then we can increase the big
10268  *        weight, to capacity - lastmininmalweightsum, e.g. :
10269  *        19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19
10270  *         ->  minimal weightsums: 5, 5, 10, 10
10271  *         ->  15 + 5 > 19 => increase 15 to 19 - 0 = 19
10272  *         ->  10 + 10 > 19 => increase 10 to 19 - 5 = 14, resulting in
10273  *        19x1 + 19x2 + 14x3 + 5x4 + 5x5  <= 19
10274  *  (3) let W(C) be the maximal weight of clique C,
10275  *          cliqueweightsum := sum(W(C))
10276  *      if cliqueweightsum - W(C) < capacity:
10277  *      - not using any item of C would make the knapsack constraint redundant
10278  *      - weights wi, i in C, and capacity can be changed to have the same redundancy effect and the same results for
10279  *        fixing xi, i in C, to zero or one, but with a reduced wi and tightened capacity to tighten the LP relaxation
10280  *      - change coefficients:
10281  *          delta     := capacity - (cliqueweightsum - W(C))
10282  *          wi'       := max(wi - delta, 0)
10283  *          capacity' := capacity - delta
10284  *      This rule has to add the used cliques in order to ensure they are enforced - otherwise, the reduction might
10285  *      introduce infeasible solutions.
10286  *  (4) for a clique C let C(xi == v) := C \ {j: xi == v -> xj == 0}),
10287  *      let cliqueweightsum(xi == v) := sum(W(C(xi == v)))
10288  *      if cliqueweightsum(xi == v) < capacity:
10289  *      - fixing variable xi to v would make the knapsack constraint redundant
10290  *      - the weight of the variable or its negation (depending on v) can be increased as long as it has the same
10291  *        redundancy effect:
10292  *          wi'       := capacity - cliqueweightsum(xi == v)
10293  *      This rule can also be applied to binary variables not in the knapsack!
10294  *  (5) if min{w} + wi > capacity:
10295  *      - using item i would force to fix other items to zero
10296  *      - wi can be increased to the capacity
10297  */
10298 static
tightenWeights(SCIP * scip,SCIP_CONS * cons,SCIP_PRESOLTIMING presoltiming,int * nchgcoefs,int * nchgsides,int * naddconss,int * ndelconss,SCIP_Bool * cutoff)10299 SCIP_RETCODE tightenWeights(
10300    SCIP*                 scip,               /**< SCIP data structure */
10301    SCIP_CONS*            cons,               /**< knapsack constraint */
10302    SCIP_PRESOLTIMING     presoltiming,       /**< current presolving timing */
10303    int*                  nchgcoefs,          /**< pointer to count total number of changed coefficients */
10304    int*                  nchgsides,          /**< pointer to count number of side changes */
10305    int*                  naddconss,          /**< pointer to count number of added constraints */
10306    int*                  ndelconss,          /**< pointer to count number of deleted constraints */
10307    SCIP_Bool*            cutoff              /**< pointer to store whether the node can be cut off */
10308    )
10309 {
10310    SCIP_CONSHDLRDATA* conshdlrdata;
10311    SCIP_CONSDATA* consdata;
10312    SCIP_Longint* weights;
10313    SCIP_Longint sumcoef;
10314    SCIP_Longint capacity;
10315    SCIP_Longint newweight;
10316    SCIP_Longint maxweight;
10317    SCIP_Longint minweight;
10318    SCIP_Bool sumcoefcase = FALSE;
10319    int startpos;
10320    int backpos;
10321    int nvars;
10322    int pos;
10323    int k;
10324    int i;
10325 
10326    assert(nchgcoefs != NULL);
10327    assert(nchgsides != NULL);
10328    assert(!SCIPconsIsModifiable(cons));
10329 
10330    conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10331    assert(conshdlrdata != NULL);
10332 
10333    consdata = SCIPconsGetData(cons);
10334    assert(consdata != NULL);
10335    assert(consdata->row == NULL); /* we are in presolve, so no LP row exists */
10336    assert(consdata->onesweightsum == 0); /* all fixed variables should have been removed */
10337    assert(consdata->weightsum > consdata->capacity); /* otherwise, the constraint is redundant */
10338    assert(consdata->nvars > 0);
10339 
10340    SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10341    if( *cutoff )
10342       return SCIP_OKAY;
10343 
10344    /* apply rule (1) */
10345    if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10346    {
10347       do
10348       {
10349          assert(consdata->merged);
10350 
10351          /* sort items, s.t. the heaviest one is in the first position */
10352          sortItems(consdata);
10353 
10354          for( i = 0; i < consdata->nvars; ++i )
10355          {
10356             SCIP_Longint weight;
10357 
10358             weight = consdata->weights[i];
10359             if( consdata->weightsum - weight < consdata->capacity )
10360             {
10361                newweight = consdata->weightsum - consdata->capacity;
10362                consdataChgWeight(consdata, i, newweight);
10363                consdata->capacity -= (weight - newweight);
10364                (*nchgcoefs)++;
10365                (*nchgsides)++;
10366                assert(!consdata->sorted);
10367                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",
10368                   SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, newweight,
10369                   consdata->capacity + (weight-newweight), consdata->capacity);
10370             }
10371             else
10372                break;
10373          }
10374       }
10375       while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10376    }
10377 
10378    /* check for redundancy */
10379    if( consdata->weightsum <= consdata->capacity )
10380       return SCIP_OKAY;
10381 
10382    pos = 0;
10383    while( pos < consdata->nvars && consdata->weights[pos] == consdata->capacity )
10384       ++pos;
10385 
10386    sumcoef = 0;
10387    weights = consdata->weights;
10388    nvars = consdata->nvars;
10389    capacity = consdata->capacity;
10390 
10391    if( (presoltiming & (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_MEDIUM)) != 0 &&
10392       pos < nvars && weights[pos] + weights[pos + 1] > capacity )
10393    {
10394       /* further reductions using the next possible coefficient sum
10395        *
10396        * e.g. 19x1 + 15x2 + 10x3 + 5x4 + 5x5 <= 19  <=>  19x1 + 19x2 + 14x3 + 5x4 + 5x5  <= 19
10397        */
10398       /* @todo loop for "k" can be extended, same coefficient when determine next sumcoef can be left out */
10399       for( k = 0; k < 4; ++k )
10400       {
10401          newweight = capacity - sumcoef;
10402 
10403          /* determine next minimal coefficient sum */
10404          switch( k )
10405          {
10406          case 0:
10407             sumcoef = weights[nvars - 1];
10408             backpos = nvars - 1;
10409             break;
10410          case 1:
10411             sumcoef = weights[nvars - 2];
10412             backpos = nvars - 2;
10413             break;
10414          case 2:
10415             if( weights[nvars - 3] < weights[nvars - 1] + weights[nvars - 2] )
10416             {
10417                sumcoefcase = TRUE;
10418                sumcoef = weights[nvars - 3];
10419                backpos = nvars - 3;
10420             }
10421             else
10422             {
10423                sumcoefcase = FALSE;
10424                sumcoef = weights[nvars - 1] + weights[nvars - 2];
10425                backpos = nvars - 2;
10426             }
10427             break;
10428          default:
10429             assert(k == 3);
10430             if( sumcoefcase )
10431             {
10432                if( weights[nvars - 4] < weights[nvars - 1] + weights[nvars - 2] )
10433                {
10434                   sumcoef = weights[nvars - 4];
10435                   backpos = nvars - 4;
10436                }
10437                else
10438                {
10439                   sumcoef = weights[nvars - 1] + weights[nvars - 2];
10440                   backpos = nvars - 2;
10441                }
10442             }
10443             else
10444             {
10445                sumcoef = weights[nvars - 3];
10446                backpos = nvars - 3;
10447             }
10448             break;
10449          }
10450 
10451          if( backpos <= pos )
10452             break;
10453 
10454          /* tighten next coefficients that, paired with the current small coefficient, exceed the capacity */
10455          maxweight = weights[pos];
10456          startpos = pos;
10457          while( 2 * maxweight > capacity && maxweight + sumcoef > capacity )
10458          {
10459             assert(newweight > weights[pos]);
10460 
10461             SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10462                SCIPconsGetName(cons), maxweight, newweight);
10463 
10464             consdataChgWeight(consdata, pos, newweight);
10465 
10466             ++pos;
10467             assert(pos < nvars);
10468 
10469             maxweight = weights[pos];
10470 
10471             if( backpos <= pos )
10472                break;
10473          }
10474          (*nchgcoefs) += (pos - startpos);
10475 
10476          /* skip unchangable weights */
10477          while( pos < nvars && weights[pos] + sumcoef == capacity )
10478             ++pos;
10479 
10480          /* check special case were there is only one weight left to tighten
10481           *
10482           * e.g.  95x1 + 59x2 + 37x3 + 36x4 <= 95 (37 > 36)
10483           *
10484           *   =>  95x1 + 59x2 + 59x3 + 36x4 <= 95
10485           *
10486           *       197x1 + 120x2 + 77x3 + 10x4 <= 207 (here we cannot tighten the coefficient further)
10487           */
10488          if( pos + 1 == backpos && weights[pos] > sumcoef &&
10489             ((k == 0) || (k == 1 && weights[nvars - 1] + sumcoef + weights[pos] > capacity)) )
10490          {
10491             newweight = capacity - sumcoef;
10492             assert(newweight > weights[pos]);
10493 
10494             SCIPdebugMsg(scip, "in constraint <%s> changing weight %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10495                SCIPconsGetName(cons), maxweight, newweight);
10496 
10497             consdataChgWeight(consdata, pos, newweight);
10498 
10499             break;
10500          }
10501 
10502          if( backpos <= pos )
10503             break;
10504       }
10505    }
10506 
10507    /* apply rule (2) (don't apply, if the knapsack has too many items for applying this costly method) */
10508    if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
10509    {
10510       if( conshdlrdata->disaggregation && consdata->nvars - pos <= MAX_USECLIQUES_SIZE && consdata->nvars >= 2 &&
10511          pos > 0 && (SCIP_Longint)consdata->nvars - pos <= consdata->capacity &&
10512          consdata->weights[pos - 1] == consdata->capacity && (pos == consdata->nvars || consdata->weights[pos] == 1) )
10513       {
10514          SCIP_VAR** clqvars;
10515          SCIP_CONS* cliquecons;
10516          char name[SCIP_MAXSTRLEN];
10517          int* clqpart;
10518          int nclqvars;
10519          int nclq;
10520          int len;
10521          int c;
10522          int w;
10523 
10524          assert(!SCIPconsIsDeleted(cons));
10525 
10526          if( pos == consdata->nvars )
10527          {
10528             SCIPdebugMsg(scip, "upgrading knapsack constraint <%s> to a set-packing constraint", SCIPconsGetName(cons));
10529 
10530             SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, SCIPconsGetName(cons), pos, consdata->vars,
10531                   SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
10532                   SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
10533                   SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
10534                   SCIPconsIsStickingAtNode(cons)) );
10535 
10536             SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10537             SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10538             ++(*naddconss);
10539 
10540             /* delete old constraint */
10541             SCIP_CALL( SCIPdelCons(scip, cons) );
10542             ++(*ndelconss);
10543 
10544             return SCIP_OKAY;
10545          }
10546 
10547          len = consdata->nvars - pos;
10548 
10549          /* allocate temporary memory */
10550          SCIP_CALL( SCIPallocBufferArray(scip, &clqpart, len) );
10551 
10552          /* calculate clique partition */
10553          SCIP_CALL( SCIPcalcCliquePartition(scip, &(consdata->vars[pos]), len, clqpart, &nclq) );
10554          assert(nclq <= len);
10555 
10556 #ifndef NDEBUG
10557          /* clique numbers must be at least as high as the index */
10558          for( w = 0; w < nclq; ++w )
10559             assert(clqpart[w] <= w);
10560 #endif
10561 
10562          SCIPdebugMsg(scip, "Disaggregating knapsack constraint <%s> due to clique information.\n", SCIPconsGetName(cons));
10563 
10564          /* allocate temporary memory */
10565          SCIP_CALL( SCIPallocBufferArray(scip, &clqvars, pos + len - nclq + 1) );
10566 
10567          /* copy corresponding variables with big coefficients */
10568          for( w = pos - 1; w >= 0; --w )
10569             clqvars[w] = consdata->vars[w];
10570 
10571          /* create for each clique a set-packing constraint */
10572          for( c = 0; c < nclq; ++c )
10573          {
10574             nclqvars = pos;
10575 
10576             for( w = c; w < len; ++w )
10577             {
10578                if( clqpart[w] == c )
10579                {
10580                   assert(nclqvars < pos + len - nclq + 1);
10581                   clqvars[nclqvars] = consdata->vars[w + pos];
10582                   ++nclqvars;
10583                }
10584             }
10585 
10586             assert(nclqvars > 1);
10587 
10588             (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, c);
10589             SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nclqvars, clqvars,
10590                   SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
10591                   SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
10592                   SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
10593                   SCIPconsIsStickingAtNode(cons)) );
10594             SCIPdebugMsg(scip, " -> adding clique constraint: ");
10595             SCIPdebugPrintCons(scip, cliquecons, NULL);
10596             SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10597             SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10598             ++(*naddconss);
10599          }
10600 
10601          /* delete old constraint */
10602          SCIP_CALL( SCIPdelCons(scip, cons) );
10603          ++(*ndelconss);
10604 
10605          SCIPfreeBufferArray(scip, &clqvars);
10606          SCIPfreeBufferArray(scip, &clqpart);
10607 
10608          return SCIP_OKAY;
10609       }
10610       else if( consdata->nvars <= MAX_USECLIQUES_SIZE || (consdata->cliquepartitioned && consdata->ncliques <= MAX_USECLIQUES_SIZE) )
10611       {
10612          SCIP_Longint* maxcliqueweights;
10613          SCIP_Longint* newweightvals;
10614          int* newweightidxs;
10615          SCIP_Longint cliqueweightsum;
10616 
10617          SCIP_CALL( SCIPallocBufferArray(scip, &maxcliqueweights, consdata->nvars) );
10618          SCIP_CALL( SCIPallocBufferArray(scip, &newweightvals, consdata->nvars) );
10619          SCIP_CALL( SCIPallocBufferArray(scip, &newweightidxs, consdata->nvars) );
10620 
10621          /* repeat as long as changes have been applied */
10622          do
10623          {
10624             int ncliques;
10625             int cliquenum;
10626             SCIP_Bool zeroweights;
10627 
10628             assert(consdata->merged);
10629 
10630             /* sort items, s.t. the heaviest one is in the first position */
10631             sortItems(consdata);
10632 
10633             /* calculate a clique partition */
10634             SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, TRUE, FALSE) );
10635 
10636             /* if there are only single element cliques, rule (2) is equivalent to rule (1) */
10637             if( consdata->cliquepartition[consdata->nvars - 1] == consdata->nvars - 1 )
10638                break;
10639 
10640             /* calculate the maximal weight of the cliques and store the clique type */
10641             cliqueweightsum = 0;
10642             ncliques = 0;
10643 
10644             for( i = 0; i < consdata->nvars; ++i )
10645             {
10646                SCIP_Longint weight;
10647 
10648                cliquenum = consdata->cliquepartition[i];
10649                assert(0 <= cliquenum && cliquenum <= ncliques);
10650 
10651                weight = consdata->weights[i];
10652                assert(weight > 0);
10653 
10654                if( cliquenum == ncliques )
10655                {
10656                   maxcliqueweights[ncliques] = weight;
10657                   cliqueweightsum += weight;
10658                   ++ncliques;
10659                }
10660 
10661                assert(maxcliqueweights[cliquenum] >= weight);
10662             }
10663 
10664             /* apply rule on every clique */
10665             zeroweights = FALSE;
10666             for( i = 0; i < ncliques; ++i )
10667             {
10668                SCIP_Longint delta;
10669 
10670                delta = consdata->capacity - (cliqueweightsum - maxcliqueweights[i]);
10671                if( delta > 0 )
10672                {
10673                   SCIP_Longint newcapacity;
10674 #ifndef NDEBUG
10675                   SCIP_Longint newmincliqueweight;
10676 #endif
10677                   SCIP_Longint newminweightsuminclique;
10678                   SCIP_Bool forceclique;
10679                   int nnewweights;
10680                   int j;
10681 
10682                   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",
10683                      SCIPconsGetName(cons), i, maxcliqueweights[i], cliqueweightsum, consdata->capacity, delta);
10684                   newcapacity = consdata->capacity - delta;
10685                   forceclique = FALSE;
10686                   nnewweights = 0;
10687 #ifndef NDEBUG
10688                   newmincliqueweight = newcapacity + 1;
10689                   for( j = 0; j < i; ++j )
10690                      assert(consdata->cliquepartition[j] < i); /* no element j < i can be in clique i */
10691 #endif
10692                   for( j = i; j < consdata->nvars; ++j )
10693                   {
10694                      if( consdata->cliquepartition[j] == i )
10695                      {
10696                         newweight = consdata->weights[j] - delta;
10697                         newweight = MAX(newweight, 0);
10698 
10699                         /* cache the new weight */
10700                         assert(nnewweights < consdata->nvars);
10701                         newweightvals[nnewweights] = newweight;
10702                         newweightidxs[nnewweights] = j;
10703                         nnewweights++;
10704 
10705 #ifndef NDEBUG
10706                         assert(newweight <= newmincliqueweight); /* items are sorted by non-increasing weight! */
10707                         newmincliqueweight = newweight;
10708 #endif
10709                      }
10710                   }
10711 
10712                   /* check if our clique information results out of this knapsack constraint and if so check if we would loose the clique information */
10713                   if( nnewweights > 1 )
10714                   {
10715 #ifndef NDEBUG
10716                      j = newweightidxs[nnewweights - 2];
10717                      assert(0 <= j && j < consdata->nvars);
10718                      assert(consdata->cliquepartition[j] == i);
10719                      j = newweightidxs[nnewweights - 1];
10720                      assert(0 <= j && j < consdata->nvars);
10721                      assert(consdata->cliquepartition[j] == i);
10722 #endif
10723 
10724                      newminweightsuminclique = newweightvals[nnewweights - 2];
10725                      newminweightsuminclique += newweightvals[nnewweights - 1];
10726 
10727                      /* check if these new two minimal weights both fit into the knapsack;
10728                       * if this is true, we have to add a clique constraint in order to enforce the clique
10729                       * (otherwise, the knapsack might have been one of the reasons for the clique, and the weight
10730                       * reduction might be infeasible, i.e., allows additional solutions)
10731                       */
10732                      if( newminweightsuminclique <= newcapacity )
10733                         forceclique = TRUE;
10734                   }
10735 
10736                   /* check if we really want to apply the change */
10737                   if( conshdlrdata->disaggregation || !forceclique )
10738                   {
10739                      SCIPdebugMsg(scip, " -> change capacity from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT " (forceclique:%u)\n",
10740                         consdata->capacity, newcapacity, forceclique);
10741                      consdata->capacity = newcapacity;
10742                      (*nchgsides)++;
10743 
10744                      for( k = 0; k < nnewweights; ++k )
10745                      {
10746                         j = newweightidxs[k];
10747                         assert(0 <= j && j < consdata->nvars);
10748                         assert(consdata->cliquepartition[j] == i);
10749 
10750                         /* apply the weight change */
10751                         SCIPdebugMsg(scip, " -> change weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10752                            SCIPvarGetName(consdata->vars[j]), consdata->weights[j], newweightvals[k]);
10753                         consdataChgWeight(consdata, j, newweightvals[k]);
10754                         (*nchgcoefs)++;
10755                         assert(!consdata->sorted);
10756                         zeroweights = zeroweights || (newweightvals[k] == 0);
10757                      }
10758                      /* if before the weight update at least one pair of weights did not fit into the knapsack and now fits,
10759                       * we have to make sure, the clique is enforced - the clique might have been constructed partially from
10760                       * this constraint, and by reducing the weights, this clique information is not contained anymore in the
10761                       * knapsack constraint
10762                       */
10763                      if( forceclique )
10764                      {
10765                         SCIP_CONS* cliquecons;
10766                         char name[SCIP_MAXSTRLEN];
10767                         SCIP_VAR** cliquevars;
10768 
10769                         SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nnewweights) );
10770                         for( k = 0; k < nnewweights; ++k )
10771                            cliquevars[k] = consdata->vars[newweightidxs[k]];
10772 
10773                         (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%" SCIP_LONGINT_FORMAT "_%d", SCIPconsGetName(cons), consdata->capacity, i);
10774                         SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, nnewweights, cliquevars,
10775                               SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
10776                               SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
10777                               SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
10778                               SCIPconsIsStickingAtNode(cons)) );
10779                         SCIPdebugMsg(scip, " -> adding clique constraint: ");
10780                         SCIPdebugPrintCons(scip, cliquecons, NULL);
10781                         SCIP_CALL( SCIPaddCons(scip, cliquecons) );
10782                         SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
10783                         SCIPfreeBufferArray(scip, &cliquevars);
10784                         (*naddconss)++;
10785                      }
10786                   }
10787                }
10788             }
10789             if( zeroweights )
10790             {
10791                SCIP_CALL( removeZeroWeights(scip, cons) );
10792             }
10793          }
10794          while( !consdata->sorted && consdata->weightsum > consdata->capacity );
10795 
10796          /* free temporary memory */
10797          SCIPfreeBufferArray(scip, &newweightidxs);
10798          SCIPfreeBufferArray(scip, &newweightvals);
10799          SCIPfreeBufferArray(scip, &maxcliqueweights);
10800 
10801          /* check for redundancy */
10802          if( consdata->weightsum <= consdata->capacity )
10803             return SCIP_OKAY;
10804       }
10805    }
10806 
10807    /* apply rule (3) */
10808    if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
10809    {
10810       SCIP_CALL( tightenWeightsLift(scip, cons, nchgcoefs, cutoff) );
10811    }
10812 
10813    /* check for redundancy */
10814    if( consdata->weightsum <= consdata->capacity )
10815       return SCIP_OKAY;
10816 
10817    if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
10818    {
10819       /* apply rule (4) (all but smallest weight) */
10820       assert(consdata->merged);
10821       sortItems(consdata);
10822       minweight = consdata->weights[consdata->nvars-1];
10823       for( i = 0; i < consdata->nvars-1; ++i )
10824       {
10825          SCIP_Longint weight;
10826 
10827          weight = consdata->weights[i];
10828          assert(weight >= minweight);
10829          if( minweight + weight > consdata->capacity )
10830          {
10831             if( weight < consdata->capacity )
10832             {
10833                SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10834                   SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), weight, consdata->capacity);
10835                assert(consdata->sorted);
10836                consdataChgWeight(consdata, i, consdata->capacity); /* this does not destroy the weight order! */
10837                assert(i == 0 || consdata->weights[i-1] >= consdata->weights[i]);
10838                consdata->sorted = TRUE;
10839                (*nchgcoefs)++;
10840             }
10841          }
10842          else
10843             break;
10844       }
10845 
10846       /* apply rule (5) (smallest weight) */
10847       if( consdata->nvars >= 2 )
10848       {
10849          SCIP_Longint weight;
10850 
10851          minweight = consdata->weights[consdata->nvars-2];
10852          weight = consdata->weights[consdata->nvars-1];
10853          assert(minweight >= weight);
10854          if( minweight + weight > consdata->capacity && weight < consdata->capacity )
10855          {
10856             SCIPdebugMsg(scip, "knapsack constraint <%s>: changed weight of <%s> from %" SCIP_LONGINT_FORMAT " to %" SCIP_LONGINT_FORMAT "\n",
10857                SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[consdata->nvars-1]), weight, consdata->capacity);
10858             assert(consdata->sorted);
10859             consdataChgWeight(consdata, consdata->nvars-1, consdata->capacity); /* this does not destroy the weight order! */
10860             assert(minweight >= consdata->weights[consdata->nvars-1]);
10861             consdata->sorted = TRUE;
10862             (*nchgcoefs)++;
10863          }
10864       }
10865    }
10866 
10867    return SCIP_OKAY;
10868 }
10869 
10870 
10871 #ifdef SCIP_DEBUG
10872 static
printClique(SCIP_VAR ** cliquevars,int ncliquevars)10873 void printClique(
10874    SCIP_VAR**            cliquevars,
10875    int                   ncliquevars
10876    )
10877 {
10878    int b;
10879    SCIPdebugMessage("adding new Clique: ");
10880    for( b = 0; b < ncliquevars; ++b )
10881       SCIPdebugPrintf("%s ", SCIPvarGetName(cliquevars[b]));
10882    SCIPdebugPrintf("\n");
10883 }
10884 #endif
10885 
10886 /** adds negated cliques of the knapsack constraint to the global clique table */
10887 static
addNegatedCliques(SCIP * const scip,SCIP_CONS * const cons,SCIP_Bool * const cutoff,int * const nbdchgs)10888 SCIP_RETCODE addNegatedCliques(
10889    SCIP*const            scip,               /**< SCIP data structure */
10890    SCIP_CONS*const       cons,               /**< knapsack constraint */
10891    SCIP_Bool*const       cutoff,             /**< pointer to store whether the node can be cut off */
10892    int*const             nbdchgs             /**< pointer to count the number of performed bound changes */
10893    )
10894 {
10895    SCIP_CONSDATA* consdata;
10896    SCIP_CONSHDLRDATA* conshdlrdata;
10897    SCIP_VAR** poscliquevars;
10898    SCIP_VAR** cliquevars;
10899    SCIP_Longint* maxweights;
10900    SCIP_Longint* gainweights;
10901    int* gaincliquepartition;
10902    SCIP_Bool* cliqueused;
10903    SCIP_Longint minactduetonegcliques;
10904    SCIP_Longint freecapacity;
10905    SCIP_Longint lastweight;
10906    SCIP_Longint beforelastweight;
10907    int nposcliquevars;
10908    int ncliquevars;
10909    int nvars;
10910    int nnegcliques;
10911    int lastcliqueused;
10912    int thisnbdchgs;
10913    int v;
10914    int w;
10915 
10916    assert(scip != NULL);
10917    assert(cons != NULL);
10918    assert(cutoff != NULL);
10919    assert(nbdchgs != NULL);
10920 
10921    *cutoff = FALSE;
10922 
10923    consdata = SCIPconsGetData(cons);
10924    assert(consdata != NULL);
10925 
10926    nvars = consdata->nvars;
10927 
10928    /* check whether the cliques have already been added */
10929    if( consdata->cliquesadded || nvars == 0 )
10930       return SCIP_OKAY;
10931 
10932    /* make sure, the items are merged */
10933    SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
10934    if( *cutoff )
10935       return SCIP_OKAY;
10936 
10937    /* make sure, items are sorted by non-increasing weight */
10938    sortItems(consdata);
10939 
10940    assert(consdata->merged);
10941 
10942    conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
10943    assert(conshdlrdata != NULL);
10944 
10945    /* calculate a clique partition */
10946    SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
10947    nnegcliques = consdata->nnegcliques;
10948 
10949    /* if we have no negated cliques, stop */
10950    if( nnegcliques == nvars )
10951       return SCIP_OKAY;
10952 
10953    /* get temporary memory */
10954    SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
10955    SCIP_CALL( SCIPallocBufferArray(scip, &cliquevars, nvars) );
10956    SCIP_CALL( SCIPallocClearBufferArray(scip, &gainweights, nvars) );
10957    SCIP_CALL( SCIPallocBufferArray(scip, &gaincliquepartition, nvars) );
10958    SCIP_CALL( SCIPallocBufferArray(scip, &maxweights, nnegcliques) );
10959    SCIP_CALL( SCIPallocClearBufferArray(scip, &cliqueused, nnegcliques) );
10960 
10961    nnegcliques = 0;
10962    minactduetonegcliques = 0;
10963 
10964    /* determine maximal weights for all negated cliques and calculate minimal weightsum due to negated cliques */
10965    for( v = 0; v < nvars; ++v )
10966    {
10967       assert(0 <= consdata->negcliquepartition[v] && consdata->negcliquepartition[v] <= nnegcliques);
10968       assert(consdata->weights[v] > 0);
10969 
10970       if( consdata->negcliquepartition[v] == nnegcliques )
10971       {
10972          nnegcliques++;
10973          maxweights[consdata->negcliquepartition[v]] = consdata->weights[v];
10974       }
10975       else
10976          minactduetonegcliques += consdata->weights[v];
10977    }
10978 
10979    nposcliquevars = 0;
10980 
10981    /* add cliques, using negated cliques information */
10982    if( minactduetonegcliques > 0 )
10983    {
10984       /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
10985       freecapacity = consdata->capacity - minactduetonegcliques;
10986 
10987       SCIPdebugPrintCons(scip, cons, NULL);
10988       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",
10989          SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
10990 
10991       /* calculate possible gain by switching chosen items in negated cliques */
10992       for( v = 0; v < nvars; ++v )
10993       {
10994          if( !cliqueused[consdata->negcliquepartition[v]] )
10995          {
10996             cliqueused[consdata->negcliquepartition[v]] = TRUE;
10997             for( w = v + 1; w < nvars; ++w )
10998             {
10999                /* if we would take the biggest weight instead of another what would we gain, take weight[v] instead of
11000                 * weight[w] (which are both in a negated clique) */
11001                if( consdata->negcliquepartition[v] == consdata->negcliquepartition[w]
11002                   && consdata->weights[v] > consdata->weights[w] )
11003                {
11004                   poscliquevars[nposcliquevars] = consdata->vars[w];
11005                   gainweights[nposcliquevars] = maxweights[consdata->negcliquepartition[v]] - consdata->weights[w];
11006                   gaincliquepartition[nposcliquevars] = consdata->negcliquepartition[v];
11007                   ++nposcliquevars;
11008                }
11009             }
11010          }
11011       }
11012 
11013       /* try to create negated cliques */
11014       if( nposcliquevars > 0 )
11015       {
11016          /* sort possible gain per substitution of the clique members */
11017          SCIPsortDownLongPtrInt(gainweights,(void**) poscliquevars, gaincliquepartition, nposcliquevars);
11018 
11019          for( v = 0; v < nposcliquevars; ++v )
11020          {
11021             SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[v], &cliquevars[0]) );
11022             ncliquevars = 1;
11023             lastweight = gainweights[v];
11024             beforelastweight = -1;
11025             lastcliqueused = gaincliquepartition[v];
11026             /* clear cliqueused to get an unused array */
11027             BMSclearMemoryArray(cliqueused, nnegcliques);
11028             cliqueused[gaincliquepartition[v]] = TRUE;
11029 
11030             /* taking bigger weights make the knapsack redundant so we will create cliques, only take items which are not
11031              * in the same negated clique and by taking two of them would exceed the free capacity */
11032             for( w = v + 1; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && gainweights[w] + lastweight > freecapacity; ++w )
11033             {
11034                beforelastweight = lastweight;
11035                lastweight = gainweights[w];
11036                lastcliqueused = gaincliquepartition[w];
11037                cliqueused[gaincliquepartition[w]] = TRUE;
11038                SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars]) );
11039                ++ncliquevars;
11040             }
11041 
11042             if( ncliquevars > 1 )
11043             {
11044                SCIPdebug( printClique(cliquevars, ncliquevars) );
11045                assert(beforelastweight > 0);
11046                /* add the clique to the clique table */
11047                /* this really happens, e.g., on enigma.mps from the short test set */
11048                SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11049                if( *cutoff )
11050                   goto TERMINATE;
11051                *nbdchgs += thisnbdchgs;
11052 
11053                /* reset last used clique to get slightly different cliques */
11054                cliqueused[lastcliqueused] = FALSE;
11055 
11056                /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11057                for( ++w; w < nposcliquevars && !cliqueused[gaincliquepartition[w]] && beforelastweight + gainweights[w] > freecapacity; ++w )
11058                {
11059                   SCIP_CALL( SCIPgetNegatedVar(scip, poscliquevars[w], &cliquevars[ncliquevars - 1]) );
11060                   SCIPdebug( printClique(cliquevars, ncliquevars) );
11061                   SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11062                   if( *cutoff )
11063                      goto TERMINATE;
11064                   *nbdchgs += thisnbdchgs;
11065                }
11066             }
11067          }
11068       }
11069    }
11070 
11071  TERMINATE:
11072    /* free temporary memory */
11073    SCIPfreeBufferArray(scip, &cliqueused);
11074    SCIPfreeBufferArray(scip, &maxweights);
11075    SCIPfreeBufferArray(scip, &gaincliquepartition);
11076    SCIPfreeBufferArray(scip, &gainweights);
11077    SCIPfreeBufferArray(scip, &cliquevars);
11078    SCIPfreeBufferArray(scip, &poscliquevars);
11079 
11080    return SCIP_OKAY;
11081 }
11082 
11083 /** greedy clique detection by considering weights and capacity
11084  *
11085  *  greedily detects cliques by first sorting the items by decreasing weights (optional) and then collecting greedily
11086  *  1) neighboring items which exceed the capacity together => one clique
11087  *  2) looping through the remaining items and finding the largest set of preceding items to build a clique => possibly many more cliques
11088  */
11089 static
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)11090 SCIP_RETCODE greedyCliqueAlgorithm(
11091    SCIP*const            scip,               /**< SCIP data structure */
11092    SCIP_VAR**            items,              /**< array of variable items */
11093    SCIP_Longint*         weights,            /**< weights of the items */
11094    int                   nitems,             /**< the number of items */
11095    SCIP_Longint          capacity,           /**< maximum free capacity of the knapsack */
11096    SCIP_Bool             sorteditems,        /**< are the items sorted by their weights nonincreasing? */
11097    SCIP_Real             cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11098    SCIP_Bool*const       cutoff,             /**< pointer to store whether the node can be cut off */
11099    int*const             nbdchgs             /**< pointer to count the number of performed bound changes */
11100    )
11101 {
11102    SCIP_Longint lastweight;
11103    int ncliquevars;
11104    int i;
11105    int thisnbdchgs;
11106 
11107    if( nitems <= 1 )
11108       return SCIP_OKAY;
11109 
11110    /* sort possible gain per substitution of the clique members */
11111    if( ! sorteditems )
11112       SCIPsortDownLongPtr(weights,(void**) items, nitems);
11113 
11114    ncliquevars = 1;
11115    lastweight = weights[0];
11116 
11117    /* taking these two weights together violates the knapsack => include into clique */
11118    for( i = 1; i < nitems && weights[i] + lastweight > capacity; ++i )
11119    {
11120       lastweight = weights[i];
11121       ++ncliquevars;
11122    }
11123 
11124    if( ncliquevars > 1 )
11125    {
11126       SCIP_Longint compareweight;
11127       SCIP_VAR** cliquevars;
11128       int compareweightidx;
11129       int minclqsize;
11130       int nnzadded;
11131 
11132       /* add the clique to the clique table */
11133       SCIPdebug( printClique(items, ncliquevars) );
11134       SCIP_CALL( SCIPaddClique(scip, items, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11135 
11136       if( *cutoff )
11137          return SCIP_OKAY;
11138 
11139       *nbdchgs += thisnbdchgs;
11140       nnzadded = ncliquevars;
11141 
11142       /* 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)*/
11143       if( ncliquevars == nitems )
11144          return SCIP_OKAY;
11145 
11146       /* copy items in order into buffer array and deduce more cliques */
11147       SCIP_CALL( SCIPduplicateBufferArray(scip, &cliquevars, items, ncliquevars) );
11148 
11149       /* try to replace the last item in the clique by a different item to obtain a slightly different clique */
11150       /* loop over remaining, smaller items and compare each item backwards against larger weights, starting with the second smallest weight */
11151       compareweightidx = ncliquevars - 2;
11152       assert(i == nitems || weights[i] + weights[ncliquevars - 1] <= capacity);
11153 
11154       /* determine minimum clique size for the following loop */
11155       minclqsize = (int)(cliqueextractfactor * ncliquevars);
11156       minclqsize = MAX(minclqsize, 2);
11157 
11158       /* loop over the remaining variables and the larger items of the first clique until we
11159        * find another clique or reach the size limit */
11160       while( compareweightidx >= 0 && i < nitems && ! (*cutoff)
11161             && ncliquevars >= minclqsize  /* stop at a given minimum clique size */
11162             && nnzadded <= 2 * nitems     /* stop if enough nonzeros were added to the cliquetable */
11163             )
11164       {
11165          compareweight = weights[compareweightidx];
11166          assert(compareweight > 0);
11167 
11168          /* include this item together with all items that have a weight at least as large as the compare weight in a clique */
11169          if( compareweight + weights[i] > capacity )
11170          {
11171             assert(compareweightidx == ncliquevars -2);
11172             cliquevars[ncliquevars - 1] = items[i];
11173             SCIPdebug( printClique(cliquevars, ncliquevars) );
11174             SCIP_CALL( SCIPaddClique(scip, cliquevars, NULL, ncliquevars, FALSE, cutoff, &thisnbdchgs) );
11175 
11176             nnzadded += ncliquevars;
11177 
11178             /* stop when there is a cutoff */
11179             if( ! (*cutoff) )
11180                *nbdchgs += thisnbdchgs;
11181 
11182             /* go to next smaller item */
11183             ++i;
11184          }
11185          else
11186          {
11187             /* choose a preceding, larger weight to compare small items against. Clique size is reduced by 1 simultaneously */
11188             compareweightidx--;
11189             ncliquevars --;
11190          }
11191       }
11192 
11193       SCIPfreeBufferArray(scip, &cliquevars);
11194    }
11195 
11196    return SCIP_OKAY;
11197 }
11198 
11199 /** adds cliques of the knapsack constraint to the global clique table */
11200 static
addCliques(SCIP * const scip,SCIP_CONS * const cons,SCIP_Real cliqueextractfactor,SCIP_Bool * const cutoff,int * const nbdchgs)11201 SCIP_RETCODE addCliques(
11202    SCIP*const            scip,               /**< SCIP data structure */
11203    SCIP_CONS*const       cons,               /**< knapsack constraint */
11204    SCIP_Real             cliqueextractfactor,/**< lower clique size limit for greedy clique extraction algorithm (relative to largest clique) */
11205    SCIP_Bool*const       cutoff,             /**< pointer to store whether the node can be cut off */
11206    int*const             nbdchgs             /**< pointer to count the number of performed bound changes */
11207    )
11208 {
11209    SCIP_CONSDATA* consdata;
11210    SCIP_CONSHDLRDATA* conshdlrdata;
11211    int i;
11212    SCIP_Longint minactduetonegcliques;
11213    SCIP_Longint freecapacity;
11214    int nnegcliques;
11215    int cliquenum;
11216    SCIP_VAR** poscliquevars;
11217    SCIP_Longint* gainweights;
11218    int nposcliquevars;
11219    SCIP_Longint* secondmaxweights;
11220    int nvars;
11221 
11222    assert(scip != NULL);
11223    assert(cons != NULL);
11224    assert(cutoff != NULL);
11225    assert(nbdchgs != NULL);
11226 
11227    *cutoff = FALSE;
11228 
11229    consdata = SCIPconsGetData(cons);
11230    assert(consdata != NULL);
11231 
11232    nvars = consdata->nvars;
11233 
11234    /* check whether the cliques have already been added */
11235    if( consdata->cliquesadded || nvars == 0 )
11236       return SCIP_OKAY;
11237 
11238    /* make sure, the items are merged */
11239    SCIP_CALL( mergeMultiples(scip, cons, cutoff) );
11240    if( *cutoff )
11241       return SCIP_OKAY;
11242 
11243    /* make sure, the items are sorted by non-increasing weight */
11244    sortItems(consdata);
11245 
11246    assert(consdata->merged);
11247 
11248    conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
11249    assert(conshdlrdata != NULL);
11250 
11251    /* calculate a clique partition */
11252    SCIP_CALL( calcCliquepartition(scip, conshdlrdata, consdata, FALSE, TRUE) );
11253    nnegcliques = consdata->nnegcliques;
11254    assert(nnegcliques <= nvars);
11255 
11256    /* get temporary memory */
11257    SCIP_CALL( SCIPallocBufferArray(scip, &poscliquevars, nvars) );
11258    SCIP_CALL( SCIPallocBufferArray(scip, &gainweights, nvars) );
11259    BMSclearMemoryArray(gainweights, nvars);
11260    SCIP_CALL( SCIPallocBufferArray(scip, &secondmaxweights, nnegcliques) );
11261    BMSclearMemoryArray(secondmaxweights, nnegcliques);
11262 
11263    minactduetonegcliques = 0;
11264 
11265    /* calculate minimal activity due to negated cliques, and determine second maximal weight in each clique */
11266    if( nnegcliques < nvars )
11267    {
11268       nnegcliques = 0;
11269 
11270       for( i = 0; i < nvars; ++i )
11271       {
11272          SCIP_Longint weight;
11273 
11274          cliquenum = consdata->negcliquepartition[i];
11275          assert(0 <= cliquenum && cliquenum <= nnegcliques);
11276 
11277          weight = consdata->weights[i];
11278          assert(weight > 0);
11279 
11280          if( cliquenum == nnegcliques )
11281             nnegcliques++;
11282          else
11283          {
11284             minactduetonegcliques += weight;
11285             if( secondmaxweights[cliquenum] == 0 )
11286                secondmaxweights[cliquenum] = weight;
11287          }
11288       }
11289    }
11290 
11291    /* add cliques, using negated cliques information */
11292    if( minactduetonegcliques > 0 )
11293    {
11294       /* free capacity is the rest of not used capacity if the smallest amount of weights due to negated cliques are used */
11295       freecapacity = consdata->capacity - minactduetonegcliques;
11296 
11297       SCIPdebugPrintCons(scip, cons, NULL);
11298       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",
11299          SCIPconsGetName(cons), consdata->capacity, minactduetonegcliques, freecapacity);
11300 
11301       /* create negated cliques out of negated cliques, if we do not take the smallest weight of a cliques ... */
11302       SCIP_CALL( addNegatedCliques(scip, cons, cutoff, nbdchgs ) );
11303 
11304       if( *cutoff )
11305          goto TERMINATE;
11306 
11307       nposcliquevars = 0;
11308 
11309       for( i = nvars - 1; i >= 0; --i )
11310       {
11311          /* if we would take the biggest weight instead of the second biggest */
11312          cliquenum = consdata->negcliquepartition[i];
11313          if( consdata->weights[i] > secondmaxweights[cliquenum] )
11314          {
11315             poscliquevars[nposcliquevars] = consdata->vars[i];
11316             gainweights[nposcliquevars] = consdata->weights[i] - secondmaxweights[cliquenum];
11317             ++nposcliquevars;
11318          }
11319       }
11320 
11321       /* use the gain weights and free capacity to derive greedily cliques */
11322       if( nposcliquevars > 1 )
11323       {
11324          SCIP_CALL( greedyCliqueAlgorithm(scip, poscliquevars, gainweights, nposcliquevars, freecapacity, FALSE, cliqueextractfactor, cutoff, nbdchgs) );
11325 
11326          if( *cutoff )
11327             goto TERMINATE;
11328       }
11329    }
11330 
11331    /* build cliques by using the items with the maximal weights */
11332    SCIP_CALL( greedyCliqueAlgorithm(scip, consdata->vars, consdata->weights, nvars, consdata->capacity, TRUE, cliqueextractfactor, cutoff, nbdchgs) );
11333 
11334    TERMINATE:
11335    /* free temporary memory and mark the constraint */
11336    SCIPfreeBufferArray(scip, &secondmaxweights);
11337    SCIPfreeBufferArray(scip, &gainweights);
11338    SCIPfreeBufferArray(scip, &poscliquevars);
11339    consdata->cliquesadded = TRUE;
11340 
11341    return SCIP_OKAY;
11342 }
11343 
11344 
11345 /** gets the key of the given element */
11346 static
SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)11347 SCIP_DECL_HASHGETKEY(hashGetKeyKnapsackcons)
11348 {  /*lint --e{715}*/
11349    /* the key is the element itself */
11350    return elem;
11351 }
11352 
11353 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
11354  * same coefficients
11355  */
11356 static
SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)11357 SCIP_DECL_HASHKEYEQ(hashKeyEqKnapsackcons)
11358 {
11359 #ifndef NDEBUG
11360    SCIP* scip;
11361 #endif
11362    SCIP_CONSDATA* consdata1;
11363    SCIP_CONSDATA* consdata2;
11364    int i;
11365 
11366    consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
11367    consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
11368    assert(consdata1->sorted);
11369    assert(consdata2->sorted);
11370 #ifndef NDEBUG
11371    scip = (SCIP*)userptr;
11372    assert(scip != NULL);
11373 #endif
11374 
11375    /* checks trivial case */
11376    if( consdata1->nvars != consdata2->nvars )
11377       return FALSE;
11378 
11379    for( i = consdata1->nvars - 1; i >= 0; --i )
11380    {
11381       /* tests if variables are equal */
11382       if( consdata1->vars[i] != consdata2->vars[i] )
11383       {
11384          assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
11385             SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
11386          return FALSE;
11387       }
11388       assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
11389 
11390       /* tests if weights are equal too */
11391       if( consdata1->weights[i] != consdata2->weights[i] )
11392          return FALSE;
11393    }
11394 
11395    return TRUE;
11396 }
11397 
11398 /** returns the hash value of the key */
11399 static
SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)11400 SCIP_DECL_HASHKEYVAL(hashKeyValKnapsackcons)
11401 {
11402 #ifndef NDEBUG
11403    SCIP* scip;
11404 #endif
11405    SCIP_CONSDATA* consdata;
11406    uint64_t firstweight;
11407    int minidx;
11408    int mididx;
11409    int maxidx;
11410 
11411    consdata = SCIPconsGetData((SCIP_CONS*)key);
11412    assert(consdata != NULL);
11413    assert(consdata->nvars > 0);
11414 
11415 #ifndef NDEBUG
11416    scip = (SCIP*)userptr;
11417    assert(scip != NULL);
11418 #endif
11419 
11420    /* sorts the constraints */
11421    sortItems(consdata);
11422 
11423    minidx = SCIPvarGetIndex(consdata->vars[0]);
11424    mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
11425    maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
11426    assert(minidx >= 0 && mididx >= 0 && maxidx >= 0);
11427 
11428    /* hash value depends on vectors of variable indices */
11429    firstweight = (uint64_t)consdata->weights[0];
11430    return SCIPhashSix(consdata->nvars, minidx, mididx, maxidx, firstweight>>32, firstweight);
11431 }
11432 
11433 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
11434  *  accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
11435  */
11436 static
detectRedundantConstraints(SCIP * scip,BMS_BLKMEM * blkmem,SCIP_CONS ** conss,int nconss,SCIP_Bool * cutoff,int * ndelconss)11437 SCIP_RETCODE detectRedundantConstraints(
11438    SCIP*                 scip,               /**< SCIP data structure */
11439    BMS_BLKMEM*           blkmem,             /**< block memory */
11440    SCIP_CONS**           conss,              /**< constraint set */
11441    int                   nconss,             /**< number of constraints in constraint set */
11442    SCIP_Bool*            cutoff,             /**< pointer to store whether the problem is infeasible */
11443    int*                  ndelconss           /**< pointer to count number of deleted constraints */
11444    )
11445 {
11446    SCIP_HASHTABLE* hashtable;
11447    int hashtablesize;
11448    int c;
11449 
11450    assert(scip != NULL);
11451    assert(blkmem != NULL);
11452    assert(conss != NULL);
11453    assert(ndelconss != NULL);
11454 
11455    /* create a hash table for the constraint set */
11456    hashtablesize = nconss;
11457    hashtablesize = MAX(hashtablesize, HASHSIZE_KNAPSACKCONS);
11458    SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
11459          hashGetKeyKnapsackcons, hashKeyEqKnapsackcons, hashKeyValKnapsackcons, (void*) scip) );
11460 
11461    /* check all constraints in the given set for redundancy */
11462    for( c = nconss - 1; c >= 0; --c )
11463    {
11464       SCIP_CONS* cons0;
11465       SCIP_CONS* cons1;
11466       SCIP_CONSDATA* consdata0;
11467 
11468       cons0 = conss[c];
11469 
11470       if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
11471          continue;
11472 
11473       consdata0 = SCIPconsGetData(cons0);
11474       assert(consdata0 != NULL);
11475       if( consdata0->nvars == 0 )
11476       {
11477          if( consdata0->capacity < 0 )
11478          {
11479             *cutoff = TRUE;
11480             goto TERMINATE;
11481          }
11482          else
11483          {
11484             SCIP_CALL( SCIPdelCons(scip, cons0) );
11485             ++(*ndelconss);
11486             continue;
11487          }
11488       }
11489 
11490       /* get constraint from current hash table with same variables and same weights as cons0 */
11491       cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
11492 
11493       if( cons1 != NULL )
11494       {
11495          SCIP_CONS* consstay;
11496          SCIP_CONS* consdel;
11497          SCIP_CONSDATA* consdata1;
11498 
11499          assert(SCIPconsIsActive(cons1));
11500          assert(!SCIPconsIsModifiable(cons1));
11501 
11502          /* constraint found: create a new constraint with same coefficients and best left and right hand side;
11503           * delete old constraints afterwards
11504           */
11505          consdata1 = SCIPconsGetData(cons1);
11506 
11507          assert(consdata1 != NULL);
11508          assert(consdata0->nvars > 0 && consdata0->nvars == consdata1->nvars);
11509 
11510          assert(consdata0->sorted && consdata1->sorted);
11511          assert(consdata0->vars[0] == consdata1->vars[0]);
11512          assert(consdata0->weights[0] == consdata1->weights[0]);
11513 
11514          SCIPdebugMsg(scip, "knapsack constraints <%s> and <%s> with equal coefficients\n",
11515             SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11516 
11517          /* check which constraint has to stay; */
11518          if( consdata0->capacity < consdata1->capacity )
11519          {
11520             consstay = cons0;
11521             consdel = cons1;
11522 
11523             /* exchange consdel with consstay in hashtable */
11524             SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) consdel) );
11525             SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) consstay) );
11526          }
11527          else
11528          {
11529             consstay = cons1;
11530             consdel = cons0;
11531          }
11532 
11533          /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11534          SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
11535 
11536          /* delete consdel */
11537          SCIP_CALL( SCIPdelCons(scip, consdel) );
11538          ++(*ndelconss);
11539 
11540          assert(SCIPconsIsActive(consstay));
11541       }
11542       else
11543       {
11544          /* no such constraint in current hash table: insert cons0 into hash table */
11545          SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
11546       }
11547    }
11548 
11549  TERMINATE:
11550    /* free hash table */
11551    SCIPhashtableFree(&hashtable);
11552 
11553    return SCIP_OKAY;
11554 }
11555 
11556 
11557 /** compares constraint with all prior constraints for possible redundancy or aggregation,
11558  *  and removes or changes constraint accordingly
11559  */
11560 static
preprocessConstraintPairs(SCIP * scip,SCIP_CONS ** conss,int firstchange,int chkind,int * ndelconss)11561 SCIP_RETCODE preprocessConstraintPairs(
11562    SCIP*                 scip,               /**< SCIP data structure */
11563    SCIP_CONS**           conss,              /**< constraint set */
11564    int                   firstchange,        /**< first constraint that changed since last pair preprocessing round */
11565    int                   chkind,             /**< index of constraint to check against all prior indices upto startind */
11566    int*                  ndelconss           /**< pointer to count number of deleted constraints */
11567    )
11568 {
11569    SCIP_CONS* cons0;
11570    SCIP_CONSDATA* consdata0;
11571    int c;
11572 
11573    assert(scip != NULL);
11574    assert(conss != NULL);
11575    assert(firstchange <= chkind);
11576    assert(ndelconss != NULL);
11577 
11578    /* get the constraint to be checked against all prior constraints */
11579    cons0 = conss[chkind];
11580    assert(cons0 != NULL);
11581    assert(SCIPconsIsActive(cons0));
11582    assert(!SCIPconsIsModifiable(cons0));
11583 
11584    consdata0 = SCIPconsGetData(cons0);
11585    assert(consdata0 != NULL);
11586    assert(consdata0->nvars >= 1);
11587    assert(consdata0->merged);
11588 
11589    /* sort the constraint */
11590    sortItems(consdata0);
11591 
11592    /* see #2970 */
11593    if( consdata0->capacity == 0 )
11594       return SCIP_OKAY;
11595 
11596    /* check constraint against all prior constraints */
11597    for( c = (consdata0->presolvedtiming == SCIP_PRESOLTIMING_EXHAUSTIVE ? firstchange : 0); c < chkind; ++c )
11598    {
11599       SCIP_CONS* cons1;
11600       SCIP_CONSDATA* consdata1;
11601       SCIP_Bool iscons0incons1contained;
11602       SCIP_Bool iscons1incons0contained;
11603       SCIP_Real quotient;
11604       int v;
11605       int v0;
11606       int v1;
11607 
11608       cons1 = conss[c];
11609       assert(cons1 != NULL);
11610       if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
11611          continue;
11612 
11613       consdata1 = SCIPconsGetData(cons1);
11614       assert(consdata1 != NULL);
11615 
11616       /* if both constraints didn't change since last pair processing, we can ignore the pair */
11617       if( consdata0->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE && consdata1->presolvedtiming >= SCIP_PRESOLTIMING_EXHAUSTIVE ) /*lint !e574*/
11618          continue;
11619 
11620       assert(consdata1->nvars >= 1);
11621       assert(consdata1->merged);
11622 
11623       /* sort the constraint */
11624       sortItems(consdata1);
11625 
11626       /* see #2970 */
11627       if( consdata1->capacity == 0 )
11628          continue;
11629 
11630       quotient = ((SCIP_Real) consdata0->capacity) / ((SCIP_Real) consdata1->capacity);
11631 
11632       if( consdata0->nvars > consdata1->nvars )
11633       {
11634          iscons0incons1contained = FALSE;
11635          iscons1incons0contained = TRUE;
11636          v = consdata1->nvars - 1;
11637       }
11638       else if( consdata0->nvars < consdata1->nvars )
11639       {
11640          iscons0incons1contained = TRUE;
11641          iscons1incons0contained = FALSE;
11642          v = consdata0->nvars - 1;
11643       }
11644       else
11645       {
11646          iscons0incons1contained = TRUE;
11647          iscons1incons0contained = TRUE;
11648          v = consdata0->nvars - 1;
11649       }
11650 
11651       SCIPdebugMsg(scip, "preprocess knapsack constraint pair <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
11652 
11653       /* check consdata0 against consdata1:
11654        * 1. if all variables var_i of cons1 are in cons0 and for each of these variables
11655        *    (consdata0->weights[i] / quotient) >= consdata1->weights[i] cons1 is redundant
11656        * 2. if all variables var_i of cons0 are in cons1 and for each of these variables
11657        *    (consdata0->weights[i] / quotient) <= consdata1->weights[i] cons0 is redundant
11658        */
11659       v0 = consdata0->nvars - 1;
11660       v1 = consdata1->nvars - 1;
11661 
11662       while( v >= 0 )
11663       {
11664          assert(iscons0incons1contained || iscons1incons0contained);
11665 
11666          /* now there are more variables in cons1 left */
11667          if( v1 > v0 )
11668          {
11669             iscons1incons0contained = FALSE;
11670             if( !iscons0incons1contained )
11671                break;
11672          }
11673          /* now there are more variables in cons0 left */
11674          else if( v1 < v0 )
11675          {
11676             iscons0incons1contained = FALSE;
11677             if( !iscons1incons0contained )
11678                break;
11679          }
11680 
11681          assert(v == v0 || v == v1);
11682          assert(v0 >= 0);
11683          assert(v1 >= 0);
11684 
11685          /* both variables are the same */
11686          if( consdata0->vars[v0] == consdata1->vars[v1] )
11687          {
11688             /* if cons1 is possible contained in cons0 (consdata0->weights[v0] / quotient) must be greater equals consdata1->weights[v1] */
11689             if( iscons1incons0contained && SCIPisLT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11690             {
11691                iscons1incons0contained = FALSE;
11692                if( !iscons0incons1contained )
11693                   break;
11694             }
11695             /* if cons0 is possible contained in cons1 (consdata0->weight[v0] / quotient) must be less equals consdata1->weight[v1] */
11696             else if( iscons0incons1contained && SCIPisGT(scip, ((SCIP_Real) consdata0->weights[v0]) / quotient, (SCIP_Real) consdata1->weights[v1]) )
11697             {
11698                iscons0incons1contained = FALSE;
11699                if( !iscons1incons0contained )
11700                   break;
11701             }
11702             --v0;
11703             --v1;
11704 	    --v;
11705          }
11706          else
11707          {
11708             /* both constraints have a variables which is not part of the other constraint, so stop */
11709             if( iscons0incons1contained && iscons1incons0contained )
11710             {
11711                iscons0incons1contained = FALSE;
11712                iscons1incons0contained = FALSE;
11713                break;
11714             }
11715             assert(iscons0incons1contained ? (v1 >= v0) : iscons1incons0contained);
11716             assert(iscons1incons0contained ? (v1 <= v0) : iscons0incons1contained);
11717             /* continue to the next variable */
11718             if( iscons0incons1contained )
11719                --v1;
11720             else
11721                --v0;
11722          }
11723       }
11724       /* neither one constraint was contained in another or we checked all variables of one constraint against the
11725        * other
11726        */
11727       assert(!iscons1incons0contained || !iscons0incons1contained || v0 == -1 || v1 == -1);
11728 
11729       if( iscons1incons0contained )
11730       {
11731          SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons1));
11732          SCIPdebugPrintCons(scip, cons1, NULL);
11733 
11734          /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11735          SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
11736 
11737          SCIP_CALL( SCIPdelCons(scip, cons1) );
11738          ++(*ndelconss);
11739       }
11740       else if( iscons0incons1contained )
11741       {
11742          SCIPdebugMsg(scip, "knapsack constraint <%s> is redundant\n", SCIPconsGetName(cons0));
11743          SCIPdebugPrintCons(scip, cons0, NULL);
11744 
11745          /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
11746          SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
11747 
11748          SCIP_CALL( SCIPdelCons(scip, cons0) );
11749          ++(*ndelconss);
11750          break;
11751       }
11752    }
11753 
11754    return SCIP_OKAY;
11755 }
11756 
11757 /** helper function to enforce constraints */
11758 static
enforceConstraint(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,int nusefulconss,SCIP_SOL * sol,SCIP_RESULT * result)11759 SCIP_RETCODE enforceConstraint(
11760    SCIP*                 scip,               /**< SCIP data structure */
11761    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
11762    SCIP_CONS**           conss,              /**< constraints to process */
11763    int                   nconss,             /**< number of constraints */
11764    int                   nusefulconss,       /**< number of useful (non-obsolete) constraints to process */
11765    SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
11766    SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
11767    )
11768 {
11769    SCIP_CONSHDLRDATA* conshdlrdata;
11770    SCIP_Bool violated;
11771    SCIP_Bool cutoff = FALSE;
11772    int maxncuts;
11773    int ncuts = 0;
11774    int i;
11775 
11776    *result = SCIP_FEASIBLE;
11777 
11778    SCIPdebugMsg(scip, "knapsack enforcement of %d/%d constraints for %s solution\n", nusefulconss, nconss,
11779          sol == NULL ? "LP" : "relaxation");
11780 
11781    /* get maximal number of cuts per round */
11782    conshdlrdata = SCIPconshdlrGetData(conshdlr);
11783    assert(conshdlrdata != NULL);
11784    maxncuts = (SCIPgetDepth(scip) == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
11785 
11786    /* search for violated useful knapsack constraints */
11787    for( i = 0; i < nusefulconss && ncuts < maxncuts && ! cutoff; i++ )
11788    {
11789       SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11790       if( violated )
11791       {
11792          /* add knapsack constraint as LP row to the relaxation */
11793          SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11794          ncuts++;
11795       }
11796    }
11797 
11798    /* as long as no violations were found, search for violated obsolete knapsack constraints */
11799    for( i = nusefulconss; i < nconss && ncuts == 0 && ! cutoff; i++ )
11800    {
11801       SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
11802       if( violated )
11803       {
11804          /* add knapsack constraint as LP row to the relaxation */
11805          SCIP_CALL( addRelaxation(scip, conss[i], &cutoff) );
11806          ncuts++;
11807       }
11808    }
11809 
11810    /* adjust the result code */
11811    if ( cutoff )
11812       *result = SCIP_CUTOFF;
11813    else if ( ncuts > 0 )
11814       *result = SCIP_SEPARATED;
11815 
11816    return SCIP_OKAY;
11817 }
11818 
11819 /*
11820  * Linear constraint upgrading
11821  */
11822 
11823 /** creates and captures a knapsack constraint out of a linear inequality */
11824 static
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)11825 SCIP_RETCODE createNormalizedKnapsack(
11826    SCIP*                 scip,               /**< SCIP data structure */
11827    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
11828    const char*           name,               /**< name of constraint */
11829    int                   nvars,              /**< number of variables in the constraint */
11830    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
11831    SCIP_Real*            vals,               /**< array with inequality coefficients */
11832    SCIP_Real             lhs,                /**< left hand side of inequality */
11833    SCIP_Real             rhs,                /**< right hand side of inequality */
11834    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
11835                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11836    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
11837                                               *   Usually set to TRUE. */
11838    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
11839                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11840    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
11841                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
11842    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
11843                                               *   Usually set to TRUE. */
11844    SCIP_Bool             local,              /**< is constraint only valid locally?
11845                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11846    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
11847                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
11848                                               *   adds coefficients to this constraint. */
11849    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
11850                                               *   Usually set to FALSE. Set to TRUE for own cuts which
11851                                               *   are separated as constraints. */
11852    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
11853                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11854    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
11855                                               *   if it may be moved to a more global node?
11856                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
11857    )
11858 {
11859    SCIP_VAR** transvars;
11860    SCIP_Longint* weights;
11861    SCIP_Longint capacity;
11862    SCIP_Longint weight;
11863    int mult;
11864    int v;
11865 
11866    assert(nvars == 0 || vars != NULL);
11867    assert(nvars == 0 || vals != NULL);
11868    assert(SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11869 
11870    /* get temporary memory */
11871    SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
11872    SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
11873 
11874    /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
11875     * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
11876     */
11877    if( SCIPisInfinity(scip, rhs) )
11878    {
11879       mult = -1;
11880       capacity = (SCIP_Longint)SCIPfeasFloor(scip, -lhs);
11881    }
11882    else
11883    {
11884       mult = +1;
11885       capacity = (SCIP_Longint)SCIPfeasFloor(scip, rhs);
11886    }
11887 
11888    /* negate positive or negative variables */
11889    for( v = 0; v < nvars; ++v )
11890    {
11891       assert(SCIPisFeasIntegral(scip, vals[v]));
11892       weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11893       if( weight > 0 )
11894       {
11895          transvars[v] = vars[v];
11896          weights[v] = weight;
11897       }
11898       else
11899       {
11900          SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
11901          weights[v] = -weight; /*lint !e2704*/
11902          capacity -= weight;
11903       }
11904       assert(transvars[v] != NULL);
11905    }
11906 
11907    /* create the constraint */
11908    SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, transvars, weights, capacity,
11909          initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
11910 
11911    /* free temporary memory */
11912    SCIPfreeBufferArray(scip, &weights);
11913    SCIPfreeBufferArray(scip, &transvars);
11914 
11915    return SCIP_OKAY;
11916 }
11917 
11918 /** tries to upgrade a linear constraint into a knapsack constraint */
11919 static
SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)11920 SCIP_DECL_LINCONSUPGD(linconsUpgdKnapsack)
11921 {  /*lint --e{715}*/
11922    SCIP_Bool upgrade;
11923 
11924    assert(upgdcons != NULL);
11925 
11926    /* check, if linear constraint can be upgraded to a knapsack constraint
11927     * - all variables must be binary
11928     * - all coefficients must be integral
11929     * - exactly one of the sides must be infinite
11930     */
11931    upgrade = (nposbin + nnegbin + nposimplbin + nnegimplbin == nvars)
11932       && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars)
11933       && (SCIPisInfinity(scip, -lhs) != SCIPisInfinity(scip, rhs));
11934 
11935    if( upgrade )
11936    {
11937       SCIPdebugMsg(scip, "upgrading constraint <%s> to knapsack constraint\n", SCIPconsGetName(cons));
11938 
11939       /* create the knapsack constraint (an automatically upgraded constraint is always unmodifiable) */
11940       assert(!SCIPconsIsModifiable(cons));
11941       SCIP_CALL( createNormalizedKnapsack(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, lhs, rhs,
11942             SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
11943             SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
11944             SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
11945             SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
11946    }
11947 
11948    return SCIP_OKAY;
11949 }
11950 
11951 
11952 /*
11953  * Callback methods of constraint handler
11954  */
11955 
11956 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11957 /**! [SnippetConsCopyKnapsack] */
11958 static
SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)11959 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyKnapsack)
11960 {  /*lint --e{715}*/
11961    assert(scip != NULL);
11962    assert(conshdlr != NULL);
11963    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11964 
11965    /* call inclusion method of constraint handler */
11966    SCIP_CALL( SCIPincludeConshdlrKnapsack(scip) );
11967 
11968    *valid = TRUE;
11969 
11970    return SCIP_OKAY;
11971 }
11972 /**! [SnippetConsCopyKnapsack] */
11973 
11974 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11975 /**! [SnippetConsFreeKnapsack] */
11976 static
SCIP_DECL_CONSFREE(consFreeKnapsack)11977 SCIP_DECL_CONSFREE(consFreeKnapsack)
11978 {  /*lint --e{715}*/
11979    SCIP_CONSHDLRDATA* conshdlrdata;
11980 
11981    /* free constraint handler data */
11982    conshdlrdata = SCIPconshdlrGetData(conshdlr);
11983    assert(conshdlrdata != NULL);
11984 
11985    SCIPfreeBlockMemory(scip, &conshdlrdata);
11986 
11987    SCIPconshdlrSetData(conshdlr, NULL);
11988 
11989    return SCIP_OKAY;
11990 }
11991 /**! [SnippetConsFreeKnapsack] */
11992 
11993 
11994 /** initialization method of constraint handler (called after problem was transformed) */
11995 static
SCIP_DECL_CONSINIT(consInitKnapsack)11996 SCIP_DECL_CONSINIT(consInitKnapsack)
11997 {  /*lint --e{715}*/
11998    SCIP_CONSHDLRDATA* conshdlrdata;
11999    int nvars;
12000 
12001    assert( scip != NULL );
12002    assert( conshdlr != NULL );
12003 
12004    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12005    assert(conshdlrdata != NULL);
12006 
12007    /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12008    nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12009 
12010    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->reals1, nvars) );
12011    conshdlrdata->reals1size = nvars;
12012 
12013    return SCIP_OKAY;
12014 }
12015 
12016 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12017 static
SCIP_DECL_CONSEXIT(consExitKnapsack)12018 SCIP_DECL_CONSEXIT(consExitKnapsack)
12019 {  /*lint --e{715}*/
12020    SCIP_CONSHDLRDATA* conshdlrdata;
12021 
12022    assert( scip != NULL );
12023    assert( conshdlr != NULL );
12024 
12025    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12026    assert(conshdlrdata != NULL);
12027 
12028    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->reals1, conshdlrdata->reals1size);
12029    conshdlrdata->reals1size = 0;
12030 
12031    return SCIP_OKAY;
12032 }
12033 
12034 
12035 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12036 static
SCIP_DECL_CONSINITPRE(consInitpreKnapsack)12037 SCIP_DECL_CONSINITPRE(consInitpreKnapsack)
12038 {  /*lint --e{715}*/
12039    SCIP_CONSHDLRDATA* conshdlrdata;
12040    int nvars;
12041 
12042    assert(scip != NULL);
12043    assert(conshdlr != NULL);
12044    assert(nconss == 0 || conss != NULL);
12045 
12046    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12047    assert(conshdlrdata != NULL);
12048 
12049    /* all variables which are of integral type can be binary; this can be checked via the method SCIPvarIsBinary(var) */
12050    nvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
12051 
12052    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints1, nvars) );
12053    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->ints2, nvars) );
12054    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints1, nvars) );
12055    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->longints2, nvars) );
12056    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools1, nvars) );
12057    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools2, nvars) );
12058    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools3, nvars) );
12059    SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bools4, nvars) );
12060 
12061    conshdlrdata->ints1size = nvars;
12062    conshdlrdata->ints2size = nvars;
12063    conshdlrdata->longints1size = nvars;
12064    conshdlrdata->longints2size = nvars;
12065    conshdlrdata->bools1size = nvars;
12066    conshdlrdata->bools2size = nvars;
12067    conshdlrdata->bools3size = nvars;
12068    conshdlrdata->bools4size = nvars;
12069 
12070 #ifdef WITH_CARDINALITY_UPGRADE
12071    conshdlrdata->upgradedcard = FALSE;
12072 #endif
12073 
12074    return SCIP_OKAY;
12075 }
12076 
12077 
12078 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12079 static
SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)12080 SCIP_DECL_CONSEXITPRE(consExitpreKnapsack)
12081 {  /*lint --e{715}*/
12082    SCIP_CONSHDLRDATA* conshdlrdata;
12083    int c;
12084 
12085    assert(scip != NULL);
12086    assert(conshdlr != NULL);
12087 
12088    for( c = 0; c < nconss; ++c )
12089    {
12090       if( !SCIPconsIsDeleted(conss[c]) )
12091       {
12092          /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
12093          SCIP_CALL( applyFixings(scip, conss[c], NULL) );
12094       }
12095    }
12096 
12097    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12098    assert(conshdlrdata != NULL);
12099 
12100    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints1, conshdlrdata->ints1size);
12101    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->ints2, conshdlrdata->ints2size);
12102    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints1, conshdlrdata->longints1size);
12103    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->longints2, conshdlrdata->longints2size);
12104    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools1, conshdlrdata->bools1size);
12105    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools2, conshdlrdata->bools2size);
12106    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools3, conshdlrdata->bools3size);
12107    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bools4, conshdlrdata->bools4size);
12108 
12109    conshdlrdata->ints1size = 0;
12110    conshdlrdata->ints2size = 0;
12111    conshdlrdata->longints1size = 0;
12112    conshdlrdata->longints2size = 0;
12113    conshdlrdata->bools1size = 0;
12114    conshdlrdata->bools2size = 0;
12115    conshdlrdata->bools3size = 0;
12116    conshdlrdata->bools4size = 0;
12117 
12118    return SCIP_OKAY;
12119 }
12120 
12121 
12122 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12123 static
SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)12124 SCIP_DECL_CONSEXITSOL(consExitsolKnapsack)
12125 {  /*lint --e{715}*/
12126    SCIP_CONSDATA* consdata;
12127    int c;
12128 
12129    assert( scip != NULL );
12130 
12131    /* release the rows of all constraints */
12132    for( c = 0; c < nconss; ++c )
12133    {
12134       consdata = SCIPconsGetData(conss[c]);
12135       assert(consdata != NULL);
12136 
12137       if( consdata->row != NULL )
12138       {
12139          SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
12140       }
12141    }
12142 
12143    return SCIP_OKAY;
12144 }
12145 
12146 /** frees specific constraint data */
12147 static
SCIP_DECL_CONSDELETE(consDeleteKnapsack)12148 SCIP_DECL_CONSDELETE(consDeleteKnapsack)
12149 {  /*lint --e{715}*/
12150    SCIP_CONSHDLRDATA* conshdlrdata;
12151 
12152    assert(conshdlr != NULL);
12153    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12154 
12155    /* get event handler */
12156    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12157    assert(conshdlrdata != NULL);
12158    assert(conshdlrdata->eventhdlr != NULL);
12159 
12160    /* free knapsack constraint */
12161    SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
12162 
12163    return SCIP_OKAY;
12164 }
12165 
12166 /** transforms constraint data into data belonging to the transformed problem */
12167 /**! [SnippetConsTransKnapsack]*/
12168 static
SCIP_DECL_CONSTRANS(consTransKnapsack)12169 SCIP_DECL_CONSTRANS(consTransKnapsack)
12170 {  /*lint --e{715}*/
12171    SCIP_CONSHDLRDATA* conshdlrdata;
12172    SCIP_CONSDATA* sourcedata;
12173    SCIP_CONSDATA* targetdata;
12174 
12175    assert(conshdlr != NULL);
12176    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12177    assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12178    assert(sourcecons != NULL);
12179    assert(targetcons != NULL);
12180 
12181    sourcedata = SCIPconsGetData(sourcecons);
12182    assert(sourcedata != NULL);
12183    assert(sourcedata->row == NULL);  /* in original problem, there cannot be LP rows */
12184 
12185    /* get event handler */
12186    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12187    assert(conshdlrdata != NULL);
12188    assert(conshdlrdata->eventhdlr != NULL);
12189 
12190    /* create target constraint data */
12191    SCIP_CALL( consdataCreate(scip, &targetdata,
12192          sourcedata->nvars, sourcedata->vars, sourcedata->weights, sourcedata->capacity) );
12193 
12194    /* create target constraint */
12195    SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12196          SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12197          SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12198          SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12199          SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12200 
12201    /* catch events for variables */
12202    SCIP_CALL( catchEvents(scip, *targetcons, targetdata, conshdlrdata->eventhdlr) );
12203 
12204    return SCIP_OKAY;
12205 }
12206 /**! [SnippetConsTransKnapsack]*/
12207 
12208 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12209 static
SCIP_DECL_CONSINITLP(consInitlpKnapsack)12210 SCIP_DECL_CONSINITLP(consInitlpKnapsack)
12211 {  /*lint --e{715}*/
12212    int i;
12213 
12214    *infeasible = FALSE;
12215 
12216    for( i = 0; i < nconss && !(*infeasible); i++ )
12217    {
12218       assert(SCIPconsIsInitial(conss[i]));
12219       SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
12220    }
12221 
12222    return SCIP_OKAY;
12223 }
12224 
12225 /** separation method of constraint handler for LP solutions */
12226 static
SCIP_DECL_CONSSEPALP(consSepalpKnapsack)12227 SCIP_DECL_CONSSEPALP(consSepalpKnapsack)
12228 {  /*lint --e{715}*/
12229    SCIP_CONSHDLRDATA* conshdlrdata;
12230    SCIP_Bool sepacardinality;
12231    SCIP_Bool cutoff;
12232 
12233    SCIP_Real loclowerbound;
12234    SCIP_Real glblowerbound;
12235    SCIP_Real cutoffbound;
12236    SCIP_Real maxbound;
12237 
12238    int depth;
12239    int nrounds;
12240    int sepafreq;
12241    int sepacardfreq;
12242    int ncuts;
12243    int maxsepacuts;
12244    int i;
12245 
12246    *result = SCIP_DIDNOTRUN;
12247 
12248    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12249    assert(conshdlrdata != NULL);
12250 
12251    depth = SCIPgetDepth(scip);
12252    nrounds = SCIPgetNSepaRounds(scip);
12253 
12254    SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12255       nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12256 
12257    /* only call the separator a given number of times at each node */
12258    if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12259       || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12260       return SCIP_OKAY;
12261 
12262    /* check, if we should additionally separate knapsack cuts */
12263    sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12264    sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12265    sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12266       && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12267 
12268    /* check dual bound to see if we want to produce knapsack cuts at this node */
12269    loclowerbound = SCIPgetLocalLowerbound(scip);
12270    glblowerbound = SCIPgetLowerbound(scip);
12271    cutoffbound = SCIPgetCutoffbound(scip);
12272    maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
12273    sepacardinality = sepacardinality && SCIPisLE(scip, loclowerbound, maxbound);
12274    sepacardinality = sepacardinality && (SCIPgetNLPBranchCands(scip) > 0);
12275 
12276    /* get the maximal number of cuts allowed in a separation round */
12277    maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12278 
12279    *result = SCIP_DIDNOTFIND;
12280    ncuts = 0;
12281    cutoff = FALSE;
12282 
12283    /* separate useful constraints */
12284    for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12285    {
12286       SCIP_CALL( separateCons(scip, conss[i], NULL, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12287    }
12288 
12289    /* adjust return value */
12290    if ( cutoff )
12291       *result = SCIP_CUTOFF;
12292    else if ( ncuts > 0 )
12293       *result = SCIP_SEPARATED;
12294 
12295    return SCIP_OKAY;
12296 }
12297 
12298 
12299 /** separation method of constraint handler for arbitrary primal solutions */
12300 static
SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)12301 SCIP_DECL_CONSSEPASOL(consSepasolKnapsack)
12302 {  /*lint --e{715}*/
12303    SCIP_CONSHDLRDATA* conshdlrdata;
12304    SCIP_Bool sepacardinality;
12305    SCIP_Bool cutoff;
12306 
12307    int depth;
12308    int nrounds;
12309    int sepafreq;
12310    int sepacardfreq;
12311    int ncuts;
12312    int maxsepacuts;
12313    int i;
12314 
12315    *result = SCIP_DIDNOTRUN;
12316 
12317    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12318    assert(conshdlrdata != NULL);
12319 
12320    depth = SCIPgetDepth(scip);
12321    nrounds = SCIPgetNSepaRounds(scip);
12322 
12323    SCIPdebugMsg(scip, "knapsack separation of %d/%d constraints, round %d (max %d/%d)\n",
12324       nusefulconss, nconss, nrounds, conshdlrdata->maxroundsroot, conshdlrdata->maxrounds);
12325 
12326    /* only call the separator a given number of times at each node */
12327    if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
12328       || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
12329       return SCIP_OKAY;
12330 
12331    /* check, if we should additionally separate knapsack cuts */
12332    sepafreq = SCIPconshdlrGetSepaFreq(conshdlr);
12333    sepacardfreq = sepafreq * conshdlrdata->sepacardfreq;
12334    sepacardinality = (conshdlrdata->sepacardfreq >= 0)
12335       && ((sepacardfreq == 0 && depth == 0) || (sepacardfreq >= 1 && (depth % sepacardfreq == 0)));
12336 
12337    /* get the maximal number of cuts allowed in a separation round */
12338    maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
12339 
12340    *result = SCIP_DIDNOTFIND;
12341    ncuts = 0;
12342    cutoff = FALSE;
12343 
12344    /* separate useful constraints */
12345    for( i = 0; i < nusefulconss && ncuts < maxsepacuts && !SCIPisStopped(scip); i++ )
12346    {
12347       SCIP_CALL( separateCons(scip, conss[i], sol, sepacardinality, conshdlrdata->usegubs, &cutoff, &ncuts) );
12348    }
12349 
12350    /* adjust return value */
12351    if ( cutoff )
12352       *result = SCIP_CUTOFF;
12353    else if( ncuts > 0 )
12354       *result = SCIP_SEPARATED;
12355 
12356    return SCIP_OKAY;
12357 }
12358 
12359 /** constraint enforcing method of constraint handler for LP solutions */
12360 static
SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)12361 SCIP_DECL_CONSENFOLP(consEnfolpKnapsack)
12362 {  /*lint --e{715}*/
12363    SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
12364 
12365    return SCIP_OKAY;
12366 }
12367 
12368 /** constraint enforcing method of constraint handler for relaxation solutions */
12369 static
SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)12370 SCIP_DECL_CONSENFORELAX(consEnforelaxKnapsack)
12371 {  /*lint --e{715}*/
12372    SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
12373 
12374    return SCIP_OKAY;
12375 }
12376 
12377 /** constraint enforcing method of constraint handler for pseudo solutions */
12378 static
SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)12379 SCIP_DECL_CONSENFOPS(consEnfopsKnapsack)
12380 {  /*lint --e{715}*/
12381    SCIP_Bool violated;
12382    int i;
12383 
12384    for( i = 0; i < nconss; i++ )
12385    {
12386       SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
12387       if( violated )
12388       {
12389          *result = SCIP_INFEASIBLE;
12390          return SCIP_OKAY;
12391       }
12392    }
12393    *result = SCIP_FEASIBLE;
12394 
12395    return SCIP_OKAY;
12396 }
12397 
12398 /** feasibility check method of constraint handler for integral solutions */
12399 static
SCIP_DECL_CONSCHECK(consCheckKnapsack)12400 SCIP_DECL_CONSCHECK(consCheckKnapsack)
12401 {  /*lint --e{715}*/
12402    SCIP_Bool violated;
12403    int i;
12404 
12405    *result = SCIP_FEASIBLE;
12406 
12407    for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
12408    {
12409       SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
12410       if( violated )
12411          *result = SCIP_INFEASIBLE;
12412    }
12413 
12414    return SCIP_OKAY;
12415 }
12416 
12417 /** domain propagation method of constraint handler */
12418 static
SCIP_DECL_CONSPROP(consPropKnapsack)12419 SCIP_DECL_CONSPROP(consPropKnapsack)
12420 {  /*lint --e{715}*/
12421    SCIP_CONSHDLRDATA* conshdlrdata;
12422    SCIP_Bool cutoff;
12423    SCIP_Bool redundant;
12424    SCIP_Bool inpresolve;
12425    int nfixedvars;
12426    int i;
12427 
12428    cutoff = FALSE;
12429    nfixedvars = 0;
12430 
12431    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12432    assert(conshdlrdata != NULL);
12433 
12434    inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
12435    assert(!inpresolve || SCIPinProbing(scip));
12436 
12437    /* process useful constraints */
12438    for( i = 0; i < nmarkedconss && !cutoff; i++ )
12439    {
12440       /* do not propagate constraints with multi-aggregated variables, which should only happen in probing mode,
12441        * otherwise the multi-aggregation should be resolved
12442        */
12443       if( inpresolve && SCIPconsGetData(conss[i])->existmultaggr )
12444          continue;
12445 #ifndef NDEBUG
12446       else
12447          assert(!(SCIPconsGetData(conss[i])->existmultaggr));
12448 #endif
12449 
12450       SCIP_CALL( propagateCons(scip, conss[i], &cutoff, &redundant, &nfixedvars, conshdlrdata->negatedclique) );
12451 
12452       /* unmark the constraint to be propagated */
12453       SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
12454    }
12455 
12456    /* adjust result code */
12457    if( cutoff )
12458       *result = SCIP_CUTOFF;
12459    else if( nfixedvars > 0 )
12460       *result = SCIP_REDUCEDDOM;
12461    else
12462       *result = SCIP_DIDNOTFIND;
12463 
12464    return SCIP_OKAY; /*lint !e438*/
12465 }
12466 
12467 /** presolving method of constraint handler */
12468 static
SCIP_DECL_CONSPRESOL(consPresolKnapsack)12469 SCIP_DECL_CONSPRESOL(consPresolKnapsack)
12470 {  /*lint --e{574,715}*/
12471    SCIP_CONSHDLRDATA* conshdlrdata;
12472    SCIP_CONSDATA* consdata;
12473    SCIP_CONS* cons;
12474    SCIP_Bool cutoff;
12475    SCIP_Bool redundant;
12476    SCIP_Bool success;
12477    int oldnfixedvars;
12478    int oldnchgbds;
12479    int oldndelconss;
12480    int oldnaddconss;
12481    int oldnchgcoefs;
12482    int oldnchgsides;
12483    int firstchange;
12484    int c;
12485    SCIP_Bool newchanges;
12486 
12487    /* remember old preprocessing counters */
12488    cutoff = FALSE;
12489    oldnfixedvars = *nfixedvars;
12490    oldnchgbds = *nchgbds;
12491    oldndelconss = *ndelconss;
12492    oldnaddconss = *naddconss;
12493    oldnchgcoefs = *nchgcoefs;
12494    oldnchgsides = *nchgsides;
12495    firstchange = INT_MAX;
12496 
12497    newchanges = (nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 || nnewupgdconss > 0);
12498 
12499    conshdlrdata = SCIPconshdlrGetData(conshdlr);
12500    assert(conshdlrdata != NULL);
12501 
12502    for( c = 0; c < nconss && !SCIPisStopped(scip); c++ )
12503    {
12504       int thisnfixedvars;
12505       int thisnchgbds;
12506 
12507       cons = conss[c];
12508       consdata = SCIPconsGetData(cons);
12509       assert(consdata != NULL);
12510 
12511       /* update data structures */
12512       /* todo if UBTIGHTENED events were caught, we could move this block after the continue */
12513       if( newchanges || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12514       {
12515          SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12516          if( cutoff )
12517             break;
12518       }
12519 
12520       /* force presolving the constraint in the initial round */
12521       if( nrounds == 0 )
12522          consdata->presolvedtiming = 0;
12523       else if( consdata->presolvedtiming >= presoltiming )
12524          continue;
12525 
12526       SCIPdebugMsg(scip, "presolving knapsack constraint <%s>\n", SCIPconsGetName(cons));
12527       SCIPdebugPrintCons(scip, cons, NULL);
12528       consdata->presolvedtiming = presoltiming;
12529 
12530       thisnfixedvars = *nfixedvars;
12531       thisnchgbds = *nchgbds;
12532 
12533       /* merge constraint, so propagation works better */
12534       SCIP_CALL( mergeMultiples(scip, cons, &cutoff) );
12535       if( cutoff )
12536          break;
12537 
12538       /* add cliques in the knapsack to the clique table */
12539       if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12540       {
12541          SCIP_CALL( addCliques(scip, cons, conshdlrdata->cliqueextractfactor, &cutoff, nchgbds) );
12542          if( cutoff )
12543             break;
12544       }
12545 
12546       /* propagate constraint */
12547       if( presoltiming < SCIP_PRESOLTIMING_EXHAUSTIVE )
12548       {
12549          SCIP_CALL( propagateCons(scip, cons, &cutoff, &redundant, nfixedvars, (presoltiming & SCIP_PRESOLTIMING_MEDIUM)) );
12550 
12551          if( cutoff )
12552             break;
12553          if( redundant )
12554          {
12555             (*ndelconss)++;
12556             continue;
12557          }
12558       }
12559 
12560       /* remove again all fixed variables, if further fixings were found */
12561       if( *nfixedvars > thisnfixedvars || *nchgbds > thisnchgbds )
12562       {
12563          SCIP_CALL( applyFixings(scip, cons, &cutoff) );
12564          if( cutoff )
12565             break;
12566 
12567          thisnfixedvars = *nfixedvars;
12568       }
12569 
12570       if( !SCIPconsIsModifiable(cons) )
12571       {
12572          /* check again for redundancy (applyFixings() might have decreased weightsum due to fixed-to-zero vars) */
12573          if( consdata->weightsum <= consdata->capacity )
12574          {
12575             SCIPdebugMsg(scip, " -> knapsack constraint <%s> is redundant: weightsum=%" SCIP_LONGINT_FORMAT ", capacity=%" SCIP_LONGINT_FORMAT "\n",
12576                SCIPconsGetName(cons), consdata->weightsum, consdata->capacity);
12577             SCIP_CALL( SCIPdelConsLocal(scip, cons) );
12578             continue;
12579          }
12580 
12581          /* divide weights by their greatest common divisor */
12582          normalizeWeights(cons, nchgcoefs, nchgsides);
12583 
12584          /* try to simplify inequalities */
12585          if( conshdlrdata->simplifyinequalities && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12586          {
12587             SCIP_CALL( simplifyInequalities(scip, cons, nfixedvars, ndelconss, nchgcoefs, nchgsides, naddconss, &cutoff) );
12588             if( cutoff )
12589                break;
12590 
12591             if( SCIPconsIsDeleted(cons) )
12592                continue;
12593 
12594             /* remove again all fixed variables, if further fixings were found */
12595             if( *nfixedvars > thisnfixedvars )
12596             {
12597                SCIP_CALL(applyFixings(scip, cons, &cutoff));
12598                if( cutoff )
12599                   break;
12600             }
12601          }
12602 
12603          /* tighten capacity and weights */
12604          SCIP_CALL( tightenWeights(scip, cons, presoltiming, nchgcoefs, nchgsides, naddconss, ndelconss, &cutoff) );
12605          if( cutoff )
12606             break;
12607 
12608          if( SCIPconsIsActive(cons) )
12609          {
12610             if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12611             {
12612                /* in case the knapsack constraints is independent of everything else, solve the knapsack and apply the
12613                 * dual reduction
12614                 */
12615                SCIP_CALL( dualPresolving(scip, cons, nchgbds, ndelconss, &redundant) );
12616                if( redundant )
12617                   continue;
12618             }
12619 
12620             /* check if knapsack constraint is parallel to objective function */
12621             SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
12622          }
12623       }
12624       /* remember the first changed constraint to begin the next aggregation round with */
12625       if( firstchange == INT_MAX && consdata->presolvedtiming != SCIP_PRESOLTIMING_EXHAUSTIVE )
12626          firstchange = c;
12627    }
12628 
12629    /* preprocess pairs of knapsack constraints */
12630    if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
12631    {
12632       /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
12633       SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &cutoff, ndelconss) );
12634    }
12635 
12636    if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) || (*naddconss != oldnaddconss) )
12637       success = TRUE;
12638    else
12639       success = FALSE;
12640 
12641    if( !cutoff && firstchange < nconss && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
12642    {
12643       SCIP_Longint npaircomparisons;
12644 
12645       npaircomparisons = 0;
12646       oldndelconss = *ndelconss;
12647       oldnchgsides = *nchgsides;
12648       oldnchgcoefs = *nchgcoefs;
12649 
12650       for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
12651       {
12652          cons = conss[c];
12653          if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
12654             continue;
12655 
12656          npaircomparisons += ((SCIPconsGetData(cons)->presolvedtiming < SCIP_PRESOLTIMING_EXHAUSTIVE) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
12657 
12658          SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, ndelconss) );
12659 
12660          if( npaircomparisons > NMINCOMPARISONS )
12661          {
12662             if( (*ndelconss != oldndelconss) || (*nchgsides != oldnchgsides) || (*nchgcoefs != oldnchgcoefs) )
12663                success = TRUE;
12664             if( ((SCIP_Real) (*ndelconss - oldndelconss) + ((SCIP_Real) (*nchgsides - oldnchgsides))/2.0 +
12665                   ((SCIP_Real) (*nchgcoefs - oldnchgcoefs))/10.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
12666                break;
12667             oldndelconss = *ndelconss;
12668             oldnchgsides = *nchgsides;
12669             oldnchgcoefs = *nchgcoefs;
12670             npaircomparisons = 0;
12671          }
12672       }
12673    }
12674 #ifdef WITH_CARDINALITY_UPGRADE
12675    /* @todo upgrade to cardinality constraints: the code below relies on disabling the checking of the knapsack
12676     * constraint in the original problem, because the upgrade ensures that at most the given number of continuous
12677     * variables has a nonzero value, but not that the binary variables corresponding to the continuous variables with
12678     * value zero are set to zero as well. This can cause problems if the user accesses the values of the binary
12679     * variables (as the MIPLIB solution checker does), or the transformed problem is freed and the original problem
12680     * (possibly with some user modifications) is re-optimized. Until there is a way to force the binary variables to 0
12681     * as well, we better keep this code disabled. */
12682    /* upgrade to cardinality constraints - only try to upgrade towards the end of presolving, since the process below is quite expensive */
12683    if ( ! cutoff && conshdlrdata->upgdcardinality && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) && ! conshdlrdata->upgradedcard )
12684    {
12685       SCIP_HASHMAP* varhash;
12686       SCIP_VAR** cardvars;
12687       SCIP_Real* cardweights;
12688       int noldupgdconss;
12689       int nscipvars;
12690       int makeupgrade;
12691 
12692       noldupgdconss = *nupgdconss;
12693       nscipvars = SCIPgetNVars(scip);
12694       SCIP_CALL( SCIPallocClearBufferArray(scip, &cardvars, nscipvars) );
12695       SCIP_CALL( SCIPallocClearBufferArray(scip, &cardweights, nscipvars) );
12696 
12697       /* set up hash map */
12698       SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nscipvars) );
12699 
12700       /* We loop through all cardinality constraints twice:
12701        * - First, determine for each binary variable the number of cardinality constraints that can be upgraded to a
12702        *   knapsack constraint and contain this variable; this number has to coincide with the number of variable up
12703        *   locks; otherwise it would be infeasible to delete the knapsack constraints after the constraint update.
12704        * - Second, upgrade knapsack constraints to cardinality constraints. */
12705       for (makeupgrade = 0; makeupgrade < 2; ++makeupgrade)
12706       {
12707          for (c = nconss-1; c >= 0 && ! SCIPisStopped(scip); --c)
12708          {
12709             SCIP_CONS* cardcons;
12710             SCIP_VAR** vars;
12711             SCIP_Longint* weights;
12712             int nvars;
12713             int v;
12714 
12715             cons = conss[c];
12716             assert( cons != NULL );
12717             consdata = SCIPconsGetData(cons);
12718             assert( consdata != NULL );
12719 
12720             nvars = consdata->nvars;
12721             vars = consdata->vars;
12722             weights = consdata->weights;
12723 
12724             /* Check, whether linear knapsack can be upgraded to a cardinality constraint:
12725              * - all variables must be binary (always true)
12726              * - all coefficients must be 1.0
12727              * - the right hand side must be smaller than nvars
12728              */
12729             if ( consdata->capacity >= nvars )
12730                continue;
12731 
12732             /* the weights are sorted: check first and last weight */
12733             assert( consdata->sorted );
12734             if ( weights[0] != 1 || weights[nvars-1] != 1 )
12735                continue;
12736 
12737             /* check whether all variables are of the form 0 <= x_v <= u_v y_v for y_v \in \{0,1\} and zero objective */
12738             for (v = 0; v < nvars; ++v)
12739             {
12740                SCIP_BOUNDTYPE* impltypes;
12741                SCIP_Real* implbounds;
12742                SCIP_VAR** implvars;
12743                SCIP_VAR* var;
12744                int nimpls;
12745                int j;
12746 
12747                var = consdata->vars[v];
12748                assert( var != NULL );
12749                assert( SCIPvarIsBinary(var) );
12750 
12751                /* ignore non-active variables */
12752                if ( ! SCIPvarIsActive(var) )
12753                   break;
12754 
12755                /* be sure that implication variable has zero objective */
12756                if ( ! SCIPisZero(scip, SCIPvarGetObj(var)) )
12757                   break;
12758 
12759                nimpls = SCIPvarGetNImpls(var, FALSE);
12760                implvars = SCIPvarGetImplVars(var, FALSE);
12761                implbounds = SCIPvarGetImplBounds(var, FALSE);
12762                impltypes = SCIPvarGetImplTypes(var, FALSE);
12763 
12764                for (j = 0; j < nimpls; ++j)
12765                {
12766                   /* be sure that continuous variable is fixed to 0 */
12767                   if ( impltypes[j] != SCIP_BOUNDTYPE_UPPER )
12768                      continue;
12769 
12770                   /* cannot currently deal with nonzero fixings */
12771                   if ( ! SCIPisZero(scip, implbounds[j]) )
12772                      continue;
12773 
12774                   /* number of down locks should be one */
12775                   if ( SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) != 1 )
12776                      continue;
12777 
12778                   cardvars[v] = implvars[j];
12779                   cardweights[v] = (SCIP_Real) v;
12780 
12781                   break;
12782                }
12783 
12784                /* found no variable upper bound candidate -> exit */
12785                if ( j >= nimpls )
12786                   break;
12787             }
12788 
12789             /* did not find fitting variable upper bound for some variable -> exit */
12790             if ( v < nvars )
12791                break;
12792 
12793             /* save number of knapsack constraints that can be upgraded to a cardinality constraint,
12794              * in which the binary variable is involved in */
12795             if ( makeupgrade == 0 )
12796             {
12797                for (v = 0; v < nvars; ++v)
12798                {
12799                   if ( SCIPhashmapExists(varhash, vars[v]) )
12800                   {
12801                      int image;
12802 
12803                      image = SCIPhashmapGetImageInt(varhash, vars[v]);
12804                      SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image + 1) );
12805                      assert( image + 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12806                   }
12807                   else
12808                   {
12809                      SCIP_CALL( SCIPhashmapInsertInt(varhash, vars[v], 1) );
12810                      assert( 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12811                      assert( SCIPhashmapExists(varhash, vars[v]) );
12812                   }
12813                }
12814             }
12815             else
12816             {
12817                SCIP_CONS* origcons;
12818 
12819                /* for each variable: check whether the number of cardinality constraints that can be upgraded to a
12820                 * knapsack constraint coincides with the number of variable up locks */
12821                for (v = 0; v < nvars; ++v)
12822                {
12823                   assert( SCIPhashmapExists(varhash, vars[v]) );
12824                   if ( SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) != SCIPhashmapGetImageInt(varhash, vars[v]) )
12825                      break;
12826                }
12827                if ( v < nvars )
12828                   break;
12829 
12830                /* store that we have upgraded */
12831                conshdlrdata->upgradedcard = TRUE;
12832 
12833                /* at this point we found suitable variable upper bounds */
12834                SCIPdebugMessage("Upgrading knapsack constraint <%s> to cardinality constraint ...\n", SCIPconsGetName(cons));
12835 
12836                /* create cardinality constraint */
12837                assert( ! SCIPconsIsModifiable(cons) );
12838                SCIP_CALL( SCIPcreateConsCardinality(scip, &cardcons, SCIPconsGetName(cons), nvars, cardvars, (int) consdata->capacity, vars, cardweights,
12839                      SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
12840                      SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
12841                      SCIPconsIsLocal(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
12842 #ifdef SCIP_DEBUG
12843                SCIPprintCons(scip, cons, NULL);
12844                SCIPinfoMessage(scip, NULL, "\n");
12845                SCIPprintCons(scip, cardcons, NULL);
12846                SCIPinfoMessage(scip, NULL, "\n");
12847 #endif
12848                SCIP_CALL( SCIPaddCons(scip, cardcons) );
12849                SCIP_CALL( SCIPreleaseCons(scip, &cardcons) );
12850                ++(*nupgdconss);
12851 
12852                /* delete oknapsack constraint */
12853                SCIP_CALL( SCIPdelCons(scip, cons) );
12854                ++(*ndelconss);
12855 
12856                /* We need to disable the original knapsack constraint, since it might happen that the binary variables
12857                 * are 1 although the continuous variables are 0. Thus, the knapsack constraint might be violated,
12858                 * although the cardinality constraint is satisfied. */
12859                origcons = SCIPfindOrigCons(scip, SCIPconsGetName(cons));
12860                assert( origcons != NULL );
12861                SCIP_CALL( SCIPsetConsChecked(scip, origcons, FALSE) );
12862 
12863                for (v = 0; v < nvars; ++v)
12864                {
12865                   int image;
12866 
12867                   assert ( SCIPhashmapExists(varhash, vars[v]) );
12868                   image = SCIPhashmapGetImageInt(varhash, vars[v]);
12869                   SCIP_CALL( SCIPhashmapSetImageInt(varhash, vars[v], image - 1) );
12870                   assert( image - 1 == SCIPhashmapGetImageInt(varhash, vars[v]) );
12871                }
12872             }
12873          }
12874       }
12875       SCIPhashmapFree(&varhash);
12876       SCIPfreeBufferArray(scip, &cardweights);
12877       SCIPfreeBufferArray(scip, &cardvars);
12878 
12879       if ( *nupgdconss > noldupgdconss )
12880          success = TRUE;
12881    }
12882 #endif
12883 
12884    if( cutoff )
12885       *result = SCIP_CUTOFF;
12886    else if( success || *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds )
12887       *result = SCIP_SUCCESS;
12888    else
12889       *result = SCIP_DIDNOTFIND;
12890 
12891    return SCIP_OKAY;
12892 }
12893 
12894 /** propagation conflict resolving method of constraint handler */
12895 static
SCIP_DECL_CONSRESPROP(consRespropKnapsack)12896 SCIP_DECL_CONSRESPROP(consRespropKnapsack)
12897 {  /*lint --e{715}*/
12898    SCIP_CONSDATA* consdata;
12899    SCIP_Longint capsum;
12900    int i;
12901 
12902    assert(result != NULL);
12903 
12904    consdata = SCIPconsGetData(cons);
12905    assert(consdata != NULL);
12906 
12907    /* check if we fixed a binary variable to one (due to negated clique) */
12908    if( inferinfo >= 0 && SCIPvarGetLbLocal(infervar) > 0.5 )
12909    {
12910       for( i = 0; i < consdata->nvars; ++i )
12911       {
12912          if( SCIPvarGetIndex(consdata->vars[i]) == inferinfo )
12913          {
12914             assert( SCIPgetVarUbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) < 0.5 );
12915             SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12916             break;
12917          }
12918       }
12919       assert(i < consdata->nvars);
12920    }
12921    else
12922    {
12923       /* according to negated cliques the minweightsum and all variables which are fixed to one which led to a fixing of
12924        * another negated clique variable to one, the inferinfo was chosen to be the negative of the position in the
12925        * knapsack constraint, see one above call of SCIPinferBinvarCons
12926        */
12927       if( inferinfo < 0 )
12928          capsum = 0;
12929       else
12930       {
12931          /* locate the inference variable and calculate the capacity that has to be used up to conclude infervar == 0;
12932           * inferinfo stores the position of the inference variable (but maybe the variables were resorted)
12933           */
12934          if( inferinfo < consdata->nvars && consdata->vars[inferinfo] == infervar )
12935             capsum = consdata->weights[inferinfo];
12936          else
12937          {
12938             for( i = 0; i < consdata->nvars && consdata->vars[i] != infervar; ++i )
12939             {}
12940             assert(i < consdata->nvars);
12941             capsum = consdata->weights[i];
12942          }
12943       }
12944 
12945       /* add fixed-to-one variables up to the point, that their weight plus the weight of the conflict variable exceeds
12946        * the capacity
12947        */
12948       if( capsum <= consdata->capacity )
12949       {
12950          for( i = 0; i < consdata->nvars; i++ )
12951          {
12952             if( SCIPgetVarLbAtIndex(scip, consdata->vars[i], bdchgidx, FALSE) > 0.5 )
12953             {
12954                SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[i]) );
12955                capsum += consdata->weights[i];
12956                if( capsum > consdata->capacity )
12957                   break;
12958             }
12959          }
12960       }
12961    }
12962 
12963    /* NOTE: It might be the case that capsum < consdata->capacity. This is due the fact that the fixing of the variable
12964     *       to zero can included negated clique information. A negated clique means, that at most one of the clique
12965     *       variables can be zero. These information can be used to compute a minimum activity of the constraint and
12966     *       used to fix variables to zero.
12967     *
12968     *       Even if capsum < consdata->capacity we still reported a complete reason since the minimum activity is based
12969     *       on global variable bounds. It might even be the case that we reported to many variables which are fixed to
12970     *       one.
12971     */
12972    *result = SCIP_SUCCESS;
12973 
12974    return SCIP_OKAY;
12975 }
12976 
12977 /** variable rounding lock method of constraint handler */
12978 /**! [SnippetConsLockKnapsack] */
12979 static
SCIP_DECL_CONSLOCK(consLockKnapsack)12980 SCIP_DECL_CONSLOCK(consLockKnapsack)
12981 {  /*lint --e{715}*/
12982    SCIP_CONSDATA* consdata;
12983    int i;
12984 
12985    consdata = SCIPconsGetData(cons);
12986    assert(consdata != NULL);
12987 
12988    for( i = 0; i < consdata->nvars; i++)
12989    {
12990       SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
12991    }
12992 
12993    return SCIP_OKAY;
12994 }
12995 /**! [SnippetConsLockKnapsack] */
12996 
12997 
12998 /** variable deletion method of constraint handler */
12999 static
SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)13000 SCIP_DECL_CONSDELVARS(consDelvarsKnapsack)
13001 {
13002    assert(scip != NULL);
13003    assert(conshdlr != NULL);
13004    assert(conss != NULL || nconss == 0);
13005 
13006    if( nconss > 0 )
13007    {
13008       SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
13009    }
13010 
13011    return SCIP_OKAY;
13012 }
13013 
13014 /** constraint display method of constraint handler */
13015 static
SCIP_DECL_CONSPRINT(consPrintKnapsack)13016 SCIP_DECL_CONSPRINT(consPrintKnapsack)
13017 {  /*lint --e{715}*/
13018    SCIP_CONSDATA* consdata;
13019    int i;
13020 
13021    assert( scip != NULL );
13022    assert( conshdlr != NULL );
13023    assert( cons != NULL );
13024 
13025    consdata = SCIPconsGetData(cons);
13026    assert(consdata != NULL);
13027 
13028    for( i = 0; i < consdata->nvars; ++i )
13029    {
13030       if( i > 0 )
13031          SCIPinfoMessage(scip, file, " ");
13032       SCIPinfoMessage(scip, file, "%+" SCIP_LONGINT_FORMAT, consdata->weights[i]);
13033       SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[i], TRUE) );
13034    }
13035    SCIPinfoMessage(scip, file, " <= %" SCIP_LONGINT_FORMAT "", consdata->capacity);
13036 
13037    return SCIP_OKAY;
13038 }
13039 
13040 /** constraint copying method of constraint handler */
13041 static
SCIP_DECL_CONSCOPY(consCopyKnapsack)13042 SCIP_DECL_CONSCOPY(consCopyKnapsack)
13043 {  /*lint --e{715}*/
13044    SCIP_VAR** sourcevars;
13045    SCIP_Longint* weights;
13046    SCIP_Real* coefs;
13047    const char* consname;
13048    int nvars;
13049    int v;
13050 
13051    /* get variables and coefficients of the source constraint */
13052    sourcevars = SCIPgetVarsKnapsack(sourcescip, sourcecons);
13053    nvars = SCIPgetNVarsKnapsack(sourcescip, sourcecons);
13054    weights = SCIPgetWeightsKnapsack(sourcescip, sourcecons);
13055 
13056    SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
13057    for( v = 0; v < nvars; ++v )
13058       coefs[v] = (SCIP_Real) weights[v];
13059 
13060    if( name != NULL )
13061       consname = name;
13062    else
13063       consname = SCIPconsGetName(sourcecons);
13064 
13065    /* copy the logic using the linear constraint copy method */
13066    SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, coefs,
13067          -SCIPinfinity(scip), (SCIP_Real) SCIPgetCapacityKnapsack(sourcescip, sourcecons), varmap, consmap,
13068          initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
13069    assert(cons != NULL);
13070 
13071    SCIPfreeBufferArray(scip, &coefs);
13072 
13073    return SCIP_OKAY;
13074 }
13075 
13076 /** constraint parsing method of constraint handler */
13077 static
SCIP_DECL_CONSPARSE(consParseKnapsack)13078 SCIP_DECL_CONSPARSE(consParseKnapsack)
13079 {  /*lint --e{715}*/
13080    SCIP_VAR* var;
13081    SCIP_Longint weight;
13082    SCIP_VAR** vars;
13083    SCIP_Longint* weights;
13084    SCIP_Longint capacity;
13085    char* endptr;
13086    int nread;
13087    int nvars;
13088    int varssize;
13089 
13090    assert(scip != NULL);
13091    assert(success != NULL);
13092    assert(str != NULL);
13093    assert(name != NULL);
13094    assert(cons != NULL);
13095 
13096    *success = TRUE;
13097 
13098    nvars = 0;
13099    varssize = 5;
13100    SCIP_CALL( SCIPallocBufferArray(scip, &vars,    varssize) );
13101    SCIP_CALL( SCIPallocBufferArray(scip, &weights, varssize) );
13102 
13103    while( *str != '\0' )
13104    {
13105       /* try to parse coefficient, and stop if not successful (probably reached <=) */
13106       if( sscanf(str, "%" SCIP_LONGINT_FORMAT "%n", &weight, &nread) < 1 )
13107          break;
13108 
13109       str += nread;
13110 
13111       /* skip whitespace */
13112       while( isspace((int)*str) )
13113          ++str;
13114 
13115       /* parse variable name */
13116       SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13117       if( var == NULL )
13118       {
13119          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
13120          *success = FALSE;
13121          break;
13122       }
13123 
13124       str = endptr;
13125 
13126       /* store weight and variable */
13127       if( varssize <= nvars )
13128       {
13129          varssize = SCIPcalcMemGrowSize(scip, varssize+1);
13130          SCIP_CALL( SCIPreallocBufferArray(scip, &vars,    varssize) );
13131          SCIP_CALL( SCIPreallocBufferArray(scip, &weights, varssize) );
13132       }
13133 
13134       vars[nvars]    = var;
13135       weights[nvars] = weight;
13136       ++nvars;
13137 
13138       /* skip whitespace */
13139       while( isspace((int)*str) )
13140          ++str;
13141    }
13142 
13143    if( *success )
13144    {
13145       if( strncmp(str, "<= ", 3) != 0 )
13146       {
13147          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '<= ' at begin of '%s'\n", str);
13148          *success = FALSE;
13149       }
13150       else
13151       {
13152          str += 3;
13153       }
13154    }
13155 
13156    if( *success )
13157    {
13158       /* coverity[secure_coding] */
13159       if( sscanf(str, "%" SCIP_LONGINT_FORMAT, &capacity) != 1 )
13160       {
13161          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing capacity from '%s'\n", str);
13162          *success = FALSE;
13163       }
13164       else
13165       {
13166 	 SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13167 	       initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13168       }
13169    }
13170 
13171    SCIPfreeBufferArray(scip, &vars);
13172    SCIPfreeBufferArray(scip, &weights);
13173 
13174    return SCIP_OKAY;
13175 }
13176 
13177 /** constraint method of constraint handler which returns the variables (if possible) */
13178 static
SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)13179 SCIP_DECL_CONSGETVARS(consGetVarsKnapsack)
13180 {  /*lint --e{715}*/
13181    SCIP_CONSDATA* consdata;
13182 
13183    consdata = SCIPconsGetData(cons);
13184    assert(consdata != NULL);
13185 
13186    if( varssize < consdata->nvars )
13187       (*success) = FALSE;
13188    else
13189    {
13190       assert(vars != NULL);
13191 
13192       BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13193       (*success) = TRUE;
13194    }
13195 
13196    return SCIP_OKAY;
13197 }
13198 
13199 /** constraint method of constraint handler which returns the number of variables (if possible) */
13200 static
SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)13201 SCIP_DECL_CONSGETNVARS(consGetNVarsKnapsack)
13202 {  /*lint --e{715}*/
13203    SCIP_CONSDATA* consdata;
13204 
13205    consdata = SCIPconsGetData(cons);
13206    assert(consdata != NULL);
13207 
13208    (*nvars) = consdata->nvars;
13209    (*success) = TRUE;
13210 
13211    return SCIP_OKAY;
13212 }
13213 
13214 /*
13215  * Event handler
13216  */
13217 
13218 /** execution method of bound change event handler */
13219 static
SCIP_DECL_EVENTEXEC(eventExecKnapsack)13220 SCIP_DECL_EVENTEXEC(eventExecKnapsack)
13221 {  /*lint --e{715}*/
13222    SCIP_CONSDATA* consdata;
13223 
13224    assert(eventdata != NULL);
13225    assert(eventdata->cons != NULL);
13226 
13227    consdata = SCIPconsGetData(eventdata->cons);
13228    assert(consdata != NULL);
13229 
13230    switch( SCIPeventGetType(event) )
13231    {
13232    case SCIP_EVENTTYPE_LBTIGHTENED:
13233       consdata->onesweightsum += eventdata->weight;
13234       consdata->presolvedtiming = 0;
13235       SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13236       break;
13237    case SCIP_EVENTTYPE_LBRELAXED:
13238       consdata->onesweightsum -= eventdata->weight;
13239       break;
13240    case SCIP_EVENTTYPE_UBTIGHTENED:
13241       consdata->presolvedtiming = 0;
13242       SCIP_CALL( SCIPmarkConsPropagate(scip, eventdata->cons) );
13243       break;
13244    case SCIP_EVENTTYPE_VARFIXED:  /* the variable should be removed from the constraint in presolving */
13245       if( !consdata->existmultaggr )
13246       {
13247          SCIP_VAR* var;
13248          var = SCIPeventGetVar(event);
13249          assert(var != NULL);
13250 
13251          /* if the variable was aggregated or multiaggregated, we must signal to propagation that we are no longer merged */
13252          if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
13253          {
13254             consdata->existmultaggr = TRUE;
13255             consdata->merged = FALSE;
13256          }
13257          else if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
13258             (SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED && SCIPvarGetStatus(SCIPvarGetNegatedVar(var)) == SCIP_VARSTATUS_AGGREGATED) )
13259             consdata->merged = FALSE;
13260       }
13261       /*lint -fallthrough*/
13262    case SCIP_EVENTTYPE_IMPLADDED: /* further preprocessing might be possible due to additional implications */
13263       consdata->presolvedtiming = 0;
13264       break;
13265    case SCIP_EVENTTYPE_VARDELETED:
13266       consdata->varsdeleted = TRUE;
13267       break;
13268    default:
13269       SCIPerrorMessage("invalid event type %lx\n", SCIPeventGetType(event));
13270       return SCIP_INVALIDDATA;
13271    }
13272 
13273    return SCIP_OKAY;
13274 }
13275 
13276 
13277 /*
13278  * constraint specific interface methods
13279  */
13280 
13281 /** creates the handler for knapsack constraints and includes it in SCIP */
SCIPincludeConshdlrKnapsack(SCIP * scip)13282 SCIP_RETCODE SCIPincludeConshdlrKnapsack(
13283    SCIP*                 scip                /**< SCIP data structure */
13284    )
13285 {
13286    SCIP_EVENTHDLRDATA* eventhdlrdata;
13287    SCIP_CONSHDLRDATA* conshdlrdata;
13288    SCIP_CONSHDLR* conshdlr;
13289 
13290    /* create knapsack constraint handler data */
13291    SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13292 
13293    /* include event handler for bound change events */
13294    eventhdlrdata = NULL;
13295    conshdlrdata->eventhdlr = NULL;
13296    SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr), EVENTHDLR_NAME, EVENTHDLR_DESC,
13297          eventExecKnapsack, eventhdlrdata) );
13298 
13299    /* get event handler for bound change events */
13300    if( conshdlrdata->eventhdlr == NULL )
13301    {
13302       SCIPerrorMessage("event handler for knapsack constraints not found\n");
13303       return SCIP_PLUGINNOTFOUND;
13304    }
13305 
13306    /* include constraint handler */
13307    SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
13308          CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
13309          consEnfolpKnapsack, consEnfopsKnapsack, consCheckKnapsack, consLockKnapsack,
13310          conshdlrdata) );
13311 
13312    assert(conshdlr != NULL);
13313 
13314    /* set non-fundamental callbacks via specific setter functions */
13315    SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyKnapsack, consCopyKnapsack) );
13316    SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteKnapsack) );
13317    SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsKnapsack) );
13318    SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitKnapsack) );
13319    SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreKnapsack) );
13320    SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolKnapsack) );
13321    SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeKnapsack) );
13322    SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsKnapsack) );
13323    SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsKnapsack) );
13324    SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitKnapsack) );
13325    SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreKnapsack) );
13326    SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpKnapsack) );
13327    SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseKnapsack) );
13328    SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolKnapsack,CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13329    SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintKnapsack) );
13330    SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropKnapsack, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13331          CONSHDLR_PROP_TIMING) );
13332    SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropKnapsack) );
13333    SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpKnapsack, consSepasolKnapsack, CONSHDLR_SEPAFREQ,
13334          CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
13335    SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransKnapsack) );
13336    SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxKnapsack) );
13337 
13338    if( SCIPfindConshdlr(scip,"linear") != NULL )
13339    {
13340       /* include the linear constraint to knapsack constraint upgrade in the linear constraint handler */
13341       SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdKnapsack, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) );
13342    }
13343 
13344    /* add knapsack constraint handler parameters */
13345    SCIP_CALL( SCIPaddIntParam(scip,
13346          "constraints/" CONSHDLR_NAME "/sepacardfreq",
13347          "multiplier on separation frequency, how often knapsack cuts are separated (-1: never, 0: only at root)",
13348          &conshdlrdata->sepacardfreq, TRUE, DEFAULT_SEPACARDFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
13349    SCIP_CALL( SCIPaddRealParam(scip,
13350          "constraints/" CONSHDLR_NAME "/maxcardbounddist",
13351          "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cuts",
13352          &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
13353    SCIP_CALL( SCIPaddRealParam(scip,
13354          "constraints/" CONSHDLR_NAME "/cliqueextractfactor",
13355          "lower clique size limit for greedy clique extraction algorithm (relative to largest clique)",
13356          &conshdlrdata->cliqueextractfactor, TRUE, DEFAULT_CLIQUEEXTRACTFACTOR, 0.0, 1.0, NULL, NULL) );
13357    SCIP_CALL( SCIPaddIntParam(scip,
13358          "constraints/" CONSHDLR_NAME "/maxrounds",
13359          "maximal number of separation rounds per node (-1: unlimited)",
13360          &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
13361    SCIP_CALL( SCIPaddIntParam(scip,
13362          "constraints/" CONSHDLR_NAME "/maxroundsroot",
13363          "maximal number of separation rounds per node in the root node (-1: unlimited)",
13364          &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
13365    SCIP_CALL( SCIPaddIntParam(scip,
13366          "constraints/" CONSHDLR_NAME "/maxsepacuts",
13367          "maximal number of cuts separated per separation round",
13368          &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
13369    SCIP_CALL( SCIPaddIntParam(scip,
13370          "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
13371          "maximal number of cuts separated per separation round in the root node",
13372          &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
13373    SCIP_CALL( SCIPaddBoolParam(scip,
13374          "constraints/" CONSHDLR_NAME "/disaggregation",
13375          "should disaggregation of knapsack constraints be allowed in preprocessing?",
13376          &conshdlrdata->disaggregation, TRUE, DEFAULT_DISAGGREGATION, NULL, NULL) );
13377    SCIP_CALL( SCIPaddBoolParam(scip,
13378          "constraints/" CONSHDLR_NAME "/simplifyinequalities",
13379          "should presolving try to simplify knapsacks",
13380          &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
13381    SCIP_CALL( SCIPaddBoolParam(scip,
13382          "constraints/" CONSHDLR_NAME "/negatedclique",
13383          "should negated clique information be used in solving process",
13384          &conshdlrdata->negatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
13385    SCIP_CALL( SCIPaddBoolParam(scip,
13386          "constraints/" CONSHDLR_NAME "/presolpairwise",
13387          "should pairwise constraint comparison be performed in presolving?",
13388          &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13389    SCIP_CALL( SCIPaddBoolParam(scip,
13390          "constraints/" CONSHDLR_NAME "/presolusehashing",
13391          "should hash table be used for detecting redundant constraints in advance",
13392          &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
13393    SCIP_CALL( SCIPaddBoolParam(scip,
13394          "constraints/" CONSHDLR_NAME "/dualpresolving",
13395          "should dual presolving steps be performed?",
13396          &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
13397    SCIP_CALL( SCIPaddBoolParam(scip,
13398          "constraints/" CONSHDLR_NAME "/usegubs",
13399          "should GUB information be used for separation?",
13400          &conshdlrdata->usegubs, TRUE, DEFAULT_USEGUBS, NULL, NULL) );
13401    SCIP_CALL( SCIPaddBoolParam(scip,
13402          "constraints/" CONSHDLR_NAME "/detectcutoffbound",
13403          "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
13404          &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
13405    SCIP_CALL( SCIPaddBoolParam(scip,
13406          "constraints/" CONSHDLR_NAME "/detectlowerbound",
13407          "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
13408          &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
13409     SCIP_CALL( SCIPaddBoolParam(scip,
13410           "constraints/" CONSHDLR_NAME "/updatecliquepartitions",
13411           "should clique partition information be updated when old partition seems outdated?",
13412           &conshdlrdata->updatecliquepartitions, TRUE, DEFAULT_UPDATECLIQUEPARTITIONS, NULL, NULL) );
13413     SCIP_CALL( SCIPaddRealParam(scip,
13414           "constraints/" CONSHDLR_NAME "/clqpartupdatefac",
13415           "factor on the growth of global cliques to decide when to update a previous "
13416           "(negated) clique partition (used only if updatecliquepartitions is set to TRUE)",
13417           &conshdlrdata->clqpartupdatefac, TRUE, DEFAULT_CLQPARTUPDATEFAC, 1.0, 10.0, NULL, NULL) );
13418 #ifdef WITH_CARDINALITY_UPGRADE
13419     SCIP_CALL( SCIPaddBoolParam(scip,
13420          "constraints/" CONSHDLR_NAME "/upgdcardinality",
13421          "if TRUE then try to update knapsack constraints to cardinality constraints",
13422          &conshdlrdata->upgdcardinality, TRUE, DEFAULT_UPGDCARDINALITY, NULL, NULL) );
13423 #endif
13424    return SCIP_OKAY;
13425 }
13426 
13427 /** creates and captures a knapsack constraint
13428  *
13429  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13430  */
13431 /**! [SnippetConsCreationKnapsack] */
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)13432 SCIP_RETCODE SCIPcreateConsKnapsack(
13433    SCIP*                 scip,               /**< SCIP data structure */
13434    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
13435    const char*           name,               /**< name of constraint */
13436    int                   nvars,              /**< number of items in the knapsack */
13437    SCIP_VAR**            vars,               /**< array with item variables */
13438    SCIP_Longint*         weights,            /**< array with item weights */
13439    SCIP_Longint          capacity,           /**< capacity of knapsack (right hand side of inequality) */
13440    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
13441                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13442    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
13443                                               *   Usually set to TRUE. */
13444    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
13445                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
13446    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
13447                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
13448    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
13449                                               *   Usually set to TRUE. */
13450    SCIP_Bool             local,              /**< is constraint only valid locally?
13451                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13452    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
13453                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
13454                                               *   adds coefficients to this constraint. */
13455    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
13456                                               *   Usually set to FALSE. Set to TRUE for own cuts which
13457                                               *   are separated as constraints. */
13458    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
13459                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13460    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
13461                                               *   if it may be moved to a more global node?
13462                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13463    )
13464 {
13465    SCIP_CONSHDLRDATA* conshdlrdata;
13466    SCIP_CONSHDLR* conshdlr;
13467    SCIP_CONSDATA* consdata;
13468 
13469    /* find the knapsack constraint handler */
13470    conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13471    if( conshdlr == NULL )
13472    {
13473       SCIPerrorMessage("knapsack constraint handler not found\n");
13474       return SCIP_PLUGINNOTFOUND;
13475    }
13476 
13477    /* get event handler */
13478    conshdlrdata = SCIPconshdlrGetData(conshdlr);
13479    assert(conshdlrdata != NULL);
13480    assert(conshdlrdata->eventhdlr != NULL);
13481 
13482    /* create constraint data */
13483    SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, weights, capacity) );
13484 
13485    /* create constraint */
13486    SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13487          local, modifiable, dynamic, removable, stickingatnode) );
13488 
13489    /* catch events for variables */
13490    if( SCIPisTransformed(scip) )
13491    {
13492       SCIP_CALL( catchEvents(scip, *cons, consdata, conshdlrdata->eventhdlr) );
13493    }
13494 
13495    return SCIP_OKAY;
13496 }
13497 /**! [SnippetConsCreationKnapsack] */
13498 
13499 /** creates and captures a knapsack constraint
13500  *  in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13501  *  method SCIPcreateConsKnapsack(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13502  *
13503  *  @see SCIPcreateConsKnapsack() for information about the basic constraint flag configuration
13504  *
13505  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13506  */
SCIPcreateConsBasicKnapsack(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Longint * weights,SCIP_Longint capacity)13507 SCIP_RETCODE SCIPcreateConsBasicKnapsack(
13508    SCIP*                 scip,               /**< SCIP data structure */
13509    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
13510    const char*           name,               /**< name of constraint */
13511    int                   nvars,              /**< number of items in the knapsack */
13512    SCIP_VAR**            vars,               /**< array with item variables */
13513    SCIP_Longint*         weights,            /**< array with item weights */
13514    SCIP_Longint          capacity            /**< capacity of knapsack */
13515    )
13516 {
13517    assert(scip != NULL);
13518 
13519    SCIP_CALL( SCIPcreateConsKnapsack(scip, cons, name, nvars, vars, weights, capacity,
13520          TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13521 
13522    return SCIP_OKAY;
13523 }
13524 
13525 /** adds new item to knapsack constraint */
SCIPaddCoefKnapsack(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Longint weight)13526 SCIP_RETCODE SCIPaddCoefKnapsack(
13527    SCIP*                 scip,               /**< SCIP data structure */
13528    SCIP_CONS*            cons,               /**< constraint data */
13529    SCIP_VAR*             var,                /**< item variable */
13530    SCIP_Longint          weight              /**< item weight */
13531    )
13532 {
13533    assert(var != NULL);
13534    assert(scip != NULL);
13535 
13536    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13537    {
13538       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13539       return SCIP_INVALIDDATA;
13540    }
13541 
13542    SCIP_CALL( addCoef(scip, cons, var, weight) );
13543 
13544    return SCIP_OKAY;
13545 }
13546 
13547 /** gets the capacity of the knapsack constraint */
SCIPgetCapacityKnapsack(SCIP * scip,SCIP_CONS * cons)13548 SCIP_Longint SCIPgetCapacityKnapsack(
13549    SCIP*                 scip,               /**< SCIP data structure */
13550    SCIP_CONS*            cons                /**< constraint data */
13551    )
13552 {
13553    SCIP_CONSDATA* consdata;
13554 
13555    assert(scip != NULL);
13556 
13557    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13558    {
13559       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13560       SCIPABORT();
13561       return 0;  /*lint !e527*/
13562    }
13563 
13564    consdata = SCIPconsGetData(cons);
13565    assert(consdata != NULL);
13566 
13567    return consdata->capacity;
13568 }
13569 
13570 /** changes capacity of the knapsack constraint
13571  *
13572  *  @note This method can only be called during problem creation stage (SCIP_STAGE_PROBLEM)
13573  */
SCIPchgCapacityKnapsack(SCIP * scip,SCIP_CONS * cons,SCIP_Longint capacity)13574 SCIP_RETCODE SCIPchgCapacityKnapsack(
13575    SCIP*                 scip,               /**< SCIP data structure */
13576    SCIP_CONS*            cons,               /**< constraint data */
13577    SCIP_Longint          capacity            /**< new capacity of knapsack */
13578    )
13579 {
13580    SCIP_CONSDATA* consdata;
13581 
13582    assert(scip != NULL);
13583 
13584    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13585    {
13586       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13587       return SCIP_INVALIDDATA;
13588    }
13589 
13590    if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13591    {
13592       SCIPerrorMessage("method can only be called during problem creation stage\n");
13593       return SCIP_INVALIDDATA;
13594    }
13595 
13596    consdata = SCIPconsGetData(cons);
13597    assert(consdata != NULL);
13598 
13599    consdata->capacity = capacity;
13600 
13601    return SCIP_OKAY;
13602 }
13603 
13604 /** gets the number of items in the knapsack constraint */
SCIPgetNVarsKnapsack(SCIP * scip,SCIP_CONS * cons)13605 int SCIPgetNVarsKnapsack(
13606    SCIP*                 scip,               /**< SCIP data structure */
13607    SCIP_CONS*            cons                /**< constraint data */
13608    )
13609 {
13610    SCIP_CONSDATA* consdata;
13611 
13612    assert(scip != NULL);
13613 
13614    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13615    {
13616       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13617       SCIPABORT();
13618       return -1;  /*lint !e527*/
13619    }
13620 
13621    consdata = SCIPconsGetData(cons);
13622    assert(consdata != NULL);
13623 
13624    return consdata->nvars;
13625 }
13626 
13627 /** gets the array of variables in the knapsack constraint; the user must not modify this array! */
SCIPgetVarsKnapsack(SCIP * scip,SCIP_CONS * cons)13628 SCIP_VAR** SCIPgetVarsKnapsack(
13629    SCIP*                 scip,               /**< SCIP data structure */
13630    SCIP_CONS*            cons                /**< constraint data */
13631    )
13632 {
13633    SCIP_CONSDATA* consdata;
13634 
13635    assert(scip != NULL);
13636 
13637    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13638    {
13639       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13640       SCIPABORT();
13641       return NULL;  /*lint !e527*/
13642    }
13643 
13644    consdata = SCIPconsGetData(cons);
13645    assert(consdata != NULL);
13646 
13647    return consdata->vars;
13648 }
13649 
13650 /** gets the array of weights in the knapsack constraint; the user must not modify this array! */
SCIPgetWeightsKnapsack(SCIP * scip,SCIP_CONS * cons)13651 SCIP_Longint* SCIPgetWeightsKnapsack(
13652    SCIP*                 scip,               /**< SCIP data structure */
13653    SCIP_CONS*            cons                /**< constraint data */
13654    )
13655 {
13656    SCIP_CONSDATA* consdata;
13657 
13658    assert(scip != NULL);
13659 
13660    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13661    {
13662       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13663       SCIPABORT();
13664       return NULL;  /*lint !e527*/
13665    }
13666 
13667    consdata = SCIPconsGetData(cons);
13668    assert(consdata != NULL);
13669 
13670    return consdata->weights;
13671 }
13672 
13673 /** gets the dual solution of the knapsack constraint in the current LP */
SCIPgetDualsolKnapsack(SCIP * scip,SCIP_CONS * cons)13674 SCIP_Real SCIPgetDualsolKnapsack(
13675    SCIP*                 scip,               /**< SCIP data structure */
13676    SCIP_CONS*            cons                /**< constraint data */
13677    )
13678 {
13679    SCIP_CONSDATA* consdata;
13680 
13681    assert(scip != NULL);
13682 
13683    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13684    {
13685       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13686       SCIPABORT();
13687       return SCIP_INVALID;  /*lint !e527*/
13688    }
13689 
13690    consdata = SCIPconsGetData(cons);
13691    assert(consdata != NULL);
13692 
13693    if( consdata->row != NULL )
13694       return SCIProwGetDualsol(consdata->row);
13695    else
13696       return 0.0;
13697 }
13698 
13699 /** gets the dual Farkas value of the knapsack constraint in the current infeasible LP */
SCIPgetDualfarkasKnapsack(SCIP * scip,SCIP_CONS * cons)13700 SCIP_Real SCIPgetDualfarkasKnapsack(
13701    SCIP*                 scip,               /**< SCIP data structure */
13702    SCIP_CONS*            cons                /**< constraint data */
13703    )
13704 {
13705    SCIP_CONSDATA* consdata;
13706 
13707    assert(scip != NULL);
13708 
13709    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13710    {
13711       SCIPerrorMessage("constraint is not a knapsack constraint\n");
13712       SCIPABORT();
13713       return SCIP_INVALID;  /*lint !e527*/
13714    }
13715 
13716    consdata = SCIPconsGetData(cons);
13717    assert(consdata != NULL);
13718 
13719    if( consdata->row != NULL )
13720       return SCIProwGetDualfarkas(consdata->row);
13721    else
13722       return 0.0;
13723 }
13724 
13725 /** returns the linear relaxation of the given knapsack constraint; may return NULL if no LP row was yet created;
13726  *  the user must not modify the row!
13727  */
SCIPgetRowKnapsack(SCIP * scip,SCIP_CONS * cons)13728 SCIP_ROW* SCIPgetRowKnapsack(
13729    SCIP*                 scip,               /**< SCIP data structure */
13730    SCIP_CONS*            cons                /**< constraint data */
13731    )
13732 {
13733    SCIP_CONSDATA* consdata;
13734 
13735    assert(scip != NULL);
13736 
13737    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13738    {
13739       SCIPerrorMessage("constraint is not a knapsack\n");
13740       SCIPABORT();
13741       return NULL;  /*lint !e527*/
13742    }
13743 
13744    consdata = SCIPconsGetData(cons);
13745    assert(consdata != NULL);
13746 
13747    return consdata->row;
13748 }
13749 
13750 /** cleans up (multi-)aggregations and fixings from knapsack constraints */
SCIPcleanupConssKnapsack(SCIP * scip,SCIP_Bool onlychecked,SCIP_Bool * infeasible)13751 SCIP_RETCODE SCIPcleanupConssKnapsack(
13752    SCIP*                 scip,               /**< SCIP data structure */
13753    SCIP_Bool             onlychecked,        /**< should only checked constraints be cleaned up? */
13754    SCIP_Bool*            infeasible          /**< pointer to return whether the problem was detected to be infeasible */
13755    )
13756 {
13757    SCIP_CONSHDLR* conshdlr;
13758    SCIP_CONS** conss;
13759    int nconss;
13760    int i;
13761 
13762    conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13763    if( conshdlr == NULL )
13764       return SCIP_OKAY;
13765 
13766    assert(infeasible != NULL);
13767    *infeasible = FALSE;
13768 
13769    nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
13770    conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
13771 
13772    for( i = 0; i < nconss; ++i )
13773    {
13774       SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
13775 
13776       if( *infeasible )
13777          break;
13778    }
13779 
13780    return SCIP_OKAY;
13781 }
13782