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_setppc.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief  Constraint handler for the set partitioning / packing / covering constraints \f$1^T x\ \{=, \le, \ge\}\ 1\f$.
19  * @author Tobias Achterberg
20  * @author Michael Winkler
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include "blockmemshell/memory.h"
26 #include "scip/cons_linear.h"
27 #include "scip/cons_quadratic.h"
28 #include "scip/cons_setppc.h"
29 #include "scip/pub_conflict.h"
30 #include "scip/pub_cons.h"
31 #include "scip/pub_event.h"
32 #include "scip/pub_lp.h"
33 #include "scip/pub_message.h"
34 #include "scip/pub_misc.h"
35 #include "scip/pub_misc_sort.h"
36 #include "scip/pub_var.h"
37 #include "scip/scip_conflict.h"
38 #include "scip/scip_cons.h"
39 #include "scip/scip_cut.h"
40 #include "scip/scip_event.h"
41 #include "scip/scip_general.h"
42 #include "scip/scip_lp.h"
43 #include "scip/scip_mem.h"
44 #include "scip/scip_message.h"
45 #include "scip/scip_numerics.h"
46 #include "scip/scip_param.h"
47 #include "scip/scip_prob.h"
48 #include "scip/scip_probing.h"
49 #include "scip/scip_randnumgen.h"
50 #include "scip/scip_sol.h"
51 #include "scip/scip_solvingstats.h"
52 #include "scip/scip_var.h"
53 #include <ctype.h>
54 #include <string.h>
55 
56 
57 #define CONSHDLR_NAME          "setppc"
58 #define CONSHDLR_DESC          "set partitioning / packing / covering constraints"
59 #define CONSHDLR_SEPAPRIORITY   +700000 /**< priority of the constraint handler for separation */
60 #define CONSHDLR_ENFOPRIORITY   -700000 /**< priority of the constraint handler for constraint enforcing */
61 #define CONSHDLR_CHECKPRIORITY  -700000 /**< priority of the constraint handler for checking feasibility */
62 #define CONSHDLR_SEPAFREQ             0 /**< frequency for separating cuts; zero means to separate only in the root node */
63 #define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
64 #define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
65                                               *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
66 #define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
67 #define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
68 #define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
69 #define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
70 
71 #define CONSHDLR_PRESOLTIMING            SCIP_PRESOLTIMING_ALWAYS
72 #define CONSHDLR_PROP_TIMING             SCIP_PROPTIMING_BEFORELP
73 
74 #define LINCONSUPGD_PRIORITY    +700000 /**< priority of the constraint handler for upgrading of linear constraints */
75 #define QUADCONSUPGD_PRIORITY   +700000 /**< priority of the constraint handler for upgrading of linear constraints */
76 
77 #define EVENTHDLR_NAME         "setppc"
78 #define EVENTHDLR_DESC         "bound change event handler for set partitioning / packing / covering constraints"
79 
80 #define CONFLICTHDLR_NAME      "setppc"
81 #define CONFLICTHDLR_DESC      "conflict handler creating set covering constraints"
82 #define CONFLICTHDLR_PRIORITY  LINCONSUPGD_PRIORITY
83 
84 #define DEFAULT_PRESOLPAIRWISE     TRUE /**< should pairwise constraint comparison be performed in presolving? */
85 
86 #define HASHSIZE_SETPPCCONS         500 /**< minimal size of hash table in setppc constraint tables */
87 #define DEFAULT_PRESOLUSEHASHING   TRUE /**< should hash table be used for detecting redundant constraints in advance */
88 #define NMINCOMPARISONS          200000 /**< number for minimal pairwise presolving comparisons */
89 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */
90 
91 #define DEFAULT_RANDSEED              3
92 
93 /*#define VARUSES*/  /* activate variable usage counting, that is necessary for LP and pseudo branching */
94 /*#define BRANCHLP*/ /* BRANCHLP is only useful if the ENFOPRIORITY is set to a positive value */
95 #ifdef BRANCHLP
96 #define MINBRANCHWEIGHT             0.3 /**< minimum weight of both sets in binary set branching */
97 #define MAXBRANCHWEIGHT             0.7 /**< maximum weight of both sets in binary set branching */
98 #endif
99 #define DEFAULT_NPSEUDOBRANCHES       2 /**< number of children created in pseudo branching (0: disable branching) */
100 #define DEFAULT_DUALPRESOLVING     TRUE /**< should dual presolving steps be performed? */
101 
102 #define DEFAULT_CLIQUELIFTING     FALSE /**< should we try to lift variables into other clique constraints, fix
103 					 *   variables, aggregate them, and also shrink the amount of variables in
104 					 *   clique constraints
105 					 */
106 #define DEFAULT_ADDVARIABLESASCLIQUES FALSE/**< should we try to generate extra clique constraint out of all binary
107                                             *   variables to hopefully fasten the detection of redundant clique
108                                             *   constraints */
109 #define DEFAULT_CLIQUESHRINKING    TRUE /**< should we try to shrink the number of variables in a clique constraints, by
110 					 *   replacing more than one variable by only one
111 					 */
112 
113 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
114 
115 /*
116  * Data structures
117  */
118 
119 /** constraint handler data */
120 struct SCIP_ConshdlrData
121 {
122    SCIP_EVENTHDLR*       eventhdlr;          /**< event handler for bound change events */
123    SCIP_CONSHDLR*        conshdlrlinear;     /**< pointer to linear constraint handler or NULL if not included */
124 #ifdef VARUSES
125    SCIP_INTARRAY*        varuses;            /**< number of times a var is used in the active setppc constraints */
126 #endif
127    SCIP_Longint          nsetpart;           /**< number of set partitioning constraints in transformed problem */
128    int                   npseudobranches;    /**< number of children created in pseudo branching (0 to disable branching) */
129    int                   noldfixedvars;      /**< number of fixed variables after last clique lifting run */
130    int                   noldimpls;          /**< number of implication before last clique lifting run */
131    int                   noldcliques;        /**< number of cliques before last clique lifting run */
132    int                   noldupgrs;          /**< number of setppc constraints since the last clique lifting run */
133    int                   nclqpresolve;       /**< number of setppc clique lifting runs */
134    SCIP_Bool             updatedsetppctype;  /**< remember whether we upgraded a constraint type */
135    SCIP_Bool             cliquelifting;      /**< should we perform the clique lifting procedure */
136    SCIP_Bool             enablecliquelifting;/**< check whether we have enough changes to run the lifting procedure again */
137    SCIP_Bool             cliqueshrinking;    /**< should we try to shrink the number of variables in a clique
138 					      *   constraints, by replacing more than one variable by only one
139 					      */
140    SCIP_Bool             addvariablesascliques;/**< should we try to generate extra clique constraint out of all binary
141                                                 *   variables to hopefully fasten the detection of redundant clique
142                                                 *   constraints */
143    SCIP_RANDNUMGEN*      randnumgen;         /**< random number generator */
144    SCIP_Bool             presolpairwise;     /**< should pairwise constraint comparison be performed in presolving? */
145    SCIP_Bool             presolusehashing;   /**< should hash table be used for detecting redundant constraints in advance */
146    SCIP_Bool             dualpresolving;     /**< should dual presolving steps be performed? */
147 };
148 
149 /** constraint data for set partitioning / packing / covering constraints */
150 struct SCIP_ConsData
151 {
152    uint64_t              signature;          /**< bit signature of vars array */
153    SCIP_ROW*             row;                /**< LP row, if constraint is already stored in LP row format */
154    SCIP_VAR**            vars;               /**< variables of the constraint */
155    int                   varssize;           /**< size of vars array */
156    int                   nvars;              /**< number of variables in the constraint */
157    int                   nfixedzeros;        /**< current number of variables fixed to zero in the constraint */
158    int                   nfixedones;         /**< current number of variables fixed to one in the constraint */
159    unsigned int          setppctype:2;       /**< type of constraint: set partitioning, packing or covering */
160    unsigned int          sorted:1;           /**< are the constraint's variables sorted? */
161    unsigned int          cliqueadded:1;      /**< was the set partitioning / packing constraint already added as clique? */
162    unsigned int          validsignature:1;   /**< is the bit signature valid? */
163    unsigned int          changed:1;          /**< was constraint changed since last redundancy round in preprocessing? */
164    unsigned int          varsdeleted:1;      /**< were variables deleted after last cleanup? */
165    unsigned int          merged:1;           /**< are the constraint's equal/negated variables already merged? */
166    unsigned int          presolpropagated:1; /**< was the constraint already propagated in presolving w.r.t. the current domains? */
167    unsigned int          existmultaggr:1;    /**< does this constraint contain aggregations */
168    unsigned int          catchevents:1;      /**< are events installed for this constraint? */
169 };
170 
171 
172 
173 
174 /*
175  * Local methods
176  */
177 
178 /** compares two active constraints of type set partitioning or set packing such that a "-1" is return if
179  *    1. the first constraint is a set partitioning constraint and the second is a set packing or
180  *    2. both constraints are set partitioning constraints and the second has more! variables than the first or
181  *    3. both constraints are set packing constraints and the second has less! variables than the first
182  *  a "0" is return if
183  *    1. both constraint are of the same type and have the amount of variables or
184  *  and a "1" is returned otherwise
185  */
186 static
setppcCompare(SCIP_CONS * const cons1,SCIP_CONS * const cons2)187 int setppcCompare(
188    SCIP_CONS*const       cons1,              /**< first problem variable */
189    SCIP_CONS*const       cons2               /**< second problem variable */
190    )
191 {
192    SCIP_CONSDATA* consdata1;
193    SCIP_CONSDATA* consdata2;
194 
195    assert(cons1 != NULL);
196    assert(cons2 != NULL);
197    assert(SCIPconsIsActive(cons1));
198    assert(SCIPconsIsActive(cons2));
199 
200    /* the partitioning type should be the smallest value and the packing the second smallest */
201    assert(SCIP_SETPPCTYPE_PARTITIONING < SCIP_SETPPCTYPE_PACKING); /*lint !e506*/
202 
203    consdata1 = SCIPconsGetData(cons1);
204    assert(consdata1 != NULL);
205    assert(consdata1->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
206    consdata2 = SCIPconsGetData(cons2);
207    assert(consdata2 != NULL);
208    assert(consdata2->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
209 
210    if( consdata1->setppctype < consdata2->setppctype ||
211       (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) || /*lint !e641*/
212       (consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars) ) /*lint !e641*/
213       return -1;
214    else if( (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars) ) /*lint !e641*/
215       return 0;
216    else
217    {
218       assert(consdata1->setppctype > consdata2->setppctype || (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->setppctype == consdata2->setppctype && consdata1->nvars > consdata2->nvars) || (consdata1->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->setppctype == consdata2->setppctype && consdata1->nvars < consdata2->nvars)); /*lint !e641*/
219       return +1;
220    }
221 }
222 
223 /** sort constraints first after type (partitioning before packing before covering) and second after number of
224  *  variables such that the partitioning constraints have increasing number of variables and the packing constraints
225  *  have decreasing number of variables */
226 static
SCIP_DECL_SORTPTRCOMP(setppcConssSort)227 SCIP_DECL_SORTPTRCOMP(setppcConssSort)
228 {
229    return setppcCompare((SCIP_CONS*)elem1, (SCIP_CONS*)elem2);
230 }
231 
232 /** compares two setppc constraints such that a "-1" is return if the first constraint is active and
233  *    1. the second constraint is deleted
234  *    2. the first constraint is a set partitioning constraint and the second is a set packing or
235  *    3. both constraints are set partitioning constraints and the second has more! variables than the first or
236  *    4. both constraints are set packing constraints and the second has less! variables than the first
237  *  a "0" is return if
238  *    1. both constraint are set-covering constraints
239  *    2. both constraint are of the same type and have the amount of variables or
240  *  and a "1" is returned otherwise
241  */
242 static
setppcCompare2(SCIP_CONS * const cons1,SCIP_CONS * const cons2)243 int setppcCompare2(
244    SCIP_CONS*const       cons1,              /**< first problem variable */
245    SCIP_CONS*const       cons2               /**< second problem variable */
246    )
247 {
248    SCIP_CONSDATA* consdata1;
249    SCIP_CONSDATA* consdata2;
250 
251    assert(cons1 != NULL);
252    assert(cons2 != NULL);
253 
254    if( SCIPconsIsDeleted(cons1) )
255    {
256       if( SCIPconsIsDeleted(cons2) )
257          return 0;
258       else
259          return +1;
260    }
261    else if( SCIPconsIsDeleted(cons2) )
262       return -1;
263 
264    consdata1 = SCIPconsGetData(cons1);
265    assert(consdata1 != NULL);
266    consdata2 = SCIPconsGetData(cons2);
267    assert(consdata2 != NULL);
268 
269    /* the partitioning type should be the smallest value and the packing the second smallest */
270    assert(SCIP_SETPPCTYPE_PARTITIONING < SCIP_SETPPCTYPE_PACKING && SCIP_SETPPCTYPE_PACKING < SCIP_SETPPCTYPE_COVERING); /*lint !e506*/
271 
272    if( consdata1->setppctype < consdata2->setppctype ||
273       ((SCIP_SETPPCTYPE)consdata1->setppctype != SCIP_SETPPCTYPE_COVERING &&
274          (((SCIP_SETPPCTYPE)consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) ||
275             ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars))) )
276       return -1;
277    else if( ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_COVERING || (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars)) )
278       return 0;
279    else
280    {
281       assert(consdata1->setppctype > consdata2->setppctype || ((consdata1->setppctype == consdata2->setppctype) &&
282             ((consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars > consdata2->nvars)
283                || (consdata1->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars < consdata2->nvars)))); /*lint !e641*/
284       return +1;
285    }
286 }
287 
288 /** sort constraints first after type (partitioning before packing before covering) and second after number of
289  *  variables such that the partitioning constraints have increasing number of variables and the packing constraints
290  *  have decreasing number of variables */
291 static
SCIP_DECL_SORTPTRCOMP(setppcConssSort2)292 SCIP_DECL_SORTPTRCOMP(setppcConssSort2)
293 {
294    return setppcCompare2((SCIP_CONS*)elem1, (SCIP_CONS*)elem2);
295 }
296 
297 
298 /** installs rounding locks for the given variable in the given setppc constraint */
299 static
lockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)300 SCIP_RETCODE lockRounding(
301    SCIP*                 scip,               /**< SCIP data structure */
302    SCIP_CONS*            cons,               /**< setppc constraint */
303    SCIP_VAR*             var                 /**< variable of constraint entry */
304    )
305 {
306    SCIP_CONSDATA* consdata;
307 
308    consdata = SCIPconsGetData(cons);
309    assert(consdata != NULL);
310 
311    switch( consdata->setppctype )
312    {
313    case SCIP_SETPPCTYPE_PARTITIONING:
314       SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
315       break;
316    case SCIP_SETPPCTYPE_PACKING:
317       SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
318       break;
319    case SCIP_SETPPCTYPE_COVERING:
320       SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, FALSE) );
321       break;
322    default:
323       SCIPerrorMessage("unknown setppc type\n");
324       return SCIP_INVALIDDATA;
325    }
326 
327    return SCIP_OKAY;
328 }
329 
330 /** removes rounding locks for the given variable in the given setppc constraint */
331 static
unlockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)332 SCIP_RETCODE unlockRounding(
333    SCIP*                 scip,               /**< SCIP data structure */
334    SCIP_CONS*            cons,               /**< setppc constraint */
335    SCIP_VAR*             var                 /**< variable of constraint entry */
336    )
337 {
338    SCIP_CONSDATA* consdata;
339 
340    consdata = SCIPconsGetData(cons);
341    assert(consdata != NULL);
342 
343    switch( consdata->setppctype )
344    {
345    case SCIP_SETPPCTYPE_PARTITIONING:
346       SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
347       break;
348    case SCIP_SETPPCTYPE_PACKING:
349       SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
350       break;
351    case SCIP_SETPPCTYPE_COVERING:
352       SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
353       break;
354    default:
355       SCIPerrorMessage("unknown setppc type\n");
356       return SCIP_INVALIDDATA;
357    }
358 
359    return SCIP_OKAY;
360 }
361 
362 /** creates constraint handler data for set partitioning / packing / covering constraint handler */
363 static
conshdlrdataCreate(SCIP * scip,SCIP_CONSHDLRDATA ** conshdlrdata,SCIP_EVENTHDLR * eventhdlr)364 SCIP_RETCODE conshdlrdataCreate(
365    SCIP*                 scip,               /**< SCIP data structure */
366    SCIP_CONSHDLRDATA**   conshdlrdata,       /**< pointer to store the constraint handler data */
367    SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
368    )
369 {
370    assert(scip != NULL);
371    assert(conshdlrdata != NULL);
372    assert(eventhdlr != NULL);
373 
374    SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
375 #ifdef VARUSES
376    SCIP_CALL( SCIPcreateIntarray(scip, &(*conshdlrdata)->varuses) );
377 #endif
378    (*conshdlrdata)->npseudobranches = DEFAULT_NPSEUDOBRANCHES;
379 
380    /* set event handler for bound change events */
381    (*conshdlrdata)->eventhdlr = eventhdlr;
382    (*conshdlrdata)->nsetpart = 0;
383 
384    /* create a random number generator */
385    SCIP_CALL( SCIPcreateRandom(scip, &(*conshdlrdata)->randnumgen,
386          DEFAULT_RANDSEED, TRUE) );
387 
388    return SCIP_OKAY;
389 }
390 
391 /** frees constraint handler data for set partitioning / packing / covering constraint handler */
392 static
conshdlrdataFree(SCIP * scip,SCIP_CONSHDLRDATA ** conshdlrdata)393 SCIP_RETCODE conshdlrdataFree(
394    SCIP*                 scip,               /**< SCIP data structure */
395    SCIP_CONSHDLRDATA**   conshdlrdata        /**< pointer to the constraint handler data */
396    )
397 {
398    assert(conshdlrdata != NULL);
399    assert(*conshdlrdata != NULL);
400 
401 #ifdef VARUSES
402    SCIP_CALL( SCIPfreeIntarray(scip, &(*conshdlrdata)->varuses) );
403 #endif
404 
405    /* free random number generator */
406    SCIPfreeRandom(scip, &(*conshdlrdata)->randnumgen);
407 
408    SCIPfreeBlockMemory(scip, conshdlrdata);
409 
410    return SCIP_OKAY;
411 }
412 
413 #ifdef VARUSES
414 /** adds the given value to the usage counter of the given variable */
415 static
conshdlrdataAddVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var,int addval)416 SCIP_RETCODE conshdlrdataAddVaruses(
417    SCIP*                 scip,               /**< SCIP data structure */
418    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
419    SCIP_VAR*             var,                /**< variable to increase usage counter for */
420    int                   addval              /**< value to add to the usage counter */
421    )
422 {
423    SCIP_INTARRAY* varuses;
424 
425    assert(conshdlrdata != NULL);
426    assert(var != NULL);
427 
428    varuses = conshdlrdata->varuses;
429    assert(varuses != NULL);
430 
431    /* if the variable is the negation of a problem variable, count the varuses in the problem variable */
432    if( SCIPvarIsNegated(var) )
433    {
434       SCIP_VAR* negvar;
435       int varindex;
436 
437       /* move the varuses value of the negated variable to the active problem variable */
438       varindex = SCIPvarGetIndex(var);
439       addval += SCIPgetIntarrayVal(scip, varuses, varindex);
440       SCIP_CALL( SCIPsetIntarrayVal(scip, varuses, varindex, 0) );
441       SCIP_CALL( SCIPgetNegatedVar(scip, var, &negvar) );
442       var = negvar;
443    }
444 
445    /* increase varuses counter */
446    SCIP_CALL( SCIPincIntarrayVal(scip, varuses, SCIPvarGetIndex(var), addval) );
447 
448    SCIPdebugMsg(scip, "added %d to varuses of <%s>: %d\n",
449       addval, SCIPvarGetName(var), SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var)));
450 
451    return SCIP_OKAY;
452 }
453 
454 /** increases the usage counter of the given variable */
455 static
conshdlrdataIncVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var)456 SCIP_RETCODE conshdlrdataIncVaruses(
457    SCIP*                 scip,               /**< SCIP data structure */
458    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
459    SCIP_VAR*             var                 /**< variable to increase usage counter for */
460    )
461 {
462    assert(conshdlrdata != NULL);
463 
464    SCIPdebugMsg(scip, "increasing varuses of <%s>: %d\n",
465       SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var)));
466 
467    SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, +1) );
468 
469    return SCIP_OKAY;
470 }
471 
472 /** decreases the usage counter of the given variable */
473 static
conshdlrdataDecVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var)474 SCIP_RETCODE conshdlrdataDecVaruses(
475    SCIP*                 scip,               /**< SCIP data structure */
476    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
477    SCIP_VAR*             var                 /**< variable to increase usage counter for */
478    )
479 {
480    assert(conshdlrdata != NULL);
481 
482    SCIPdebugMsg(scip, "decreasing varuses of <%s>: %d\n",
483       SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var)));
484 
485    SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, -1) );
486 
487    return SCIP_OKAY;
488 }
489 
490 /** increases the usage counter of all variable in the constraint */
491 static
consdataIncVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONSDATA * consdata)492 SCIP_RETCODE consdataIncVaruses(
493    SCIP*                 scip,               /**< SCIP data structure */
494    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
495    SCIP_CONSDATA*        consdata            /**< setppc constraint data */
496    )
497 {
498    int v;
499 
500    assert(consdata != NULL);
501 
502    for( v = 0; v < consdata->nvars; ++v )
503    {
504       SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, consdata->vars[v]) );
505    }
506 
507    return SCIP_OKAY;
508 }
509 
510 /** decreases the usage counter of all variable in the constraint */
511 static
consdataDecVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONSDATA * consdata)512 SCIP_RETCODE consdataDecVaruses(
513    SCIP*                 scip,               /**< SCIP data structure */
514    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
515    SCIP_CONSDATA*        consdata            /**< setppc constraint data */
516    )
517 {
518    int v;
519 
520    assert(consdata != NULL);
521 
522    for( v = 0; v < consdata->nvars; ++v )
523    {
524       SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, consdata->vars[v]) );
525    }
526 
527    return SCIP_OKAY;
528 }
529 #endif
530 
531 /** ensures, that the vars array can store at least num entries */
532 static
consdataEnsureVarsSize(SCIP * scip,SCIP_CONSDATA * consdata,int num)533 SCIP_RETCODE consdataEnsureVarsSize(
534    SCIP*                 scip,               /**< SCIP data structure */
535    SCIP_CONSDATA*        consdata,           /**< setppc constraint data */
536    int                   num                 /**< minimum number of entries to store */
537    )
538 {
539    assert(consdata != NULL);
540    assert(consdata->nvars <= consdata->varssize);
541 
542    if( num > consdata->varssize )
543    {
544       int newsize;
545 
546       newsize = SCIPcalcMemGrowSize(scip, num);
547       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
548       consdata->varssize = newsize;
549    }
550    assert(num <= consdata->varssize);
551 
552    return SCIP_OKAY;
553 }
554 
555 /** creates a set partitioning / packing / covering constraint data object */
556 static
consdataCreate(SCIP * scip,SCIP_CONSDATA ** consdata,int nvars,SCIP_VAR ** vars,SCIP_SETPPCTYPE setppctype)557 SCIP_RETCODE consdataCreate(
558    SCIP*                 scip,               /**< SCIP data structure */
559    SCIP_CONSDATA**       consdata,           /**< pointer to store the set partitioning / packing / covering constraint */
560    int                   nvars,              /**< number of variables in the constraint */
561    SCIP_VAR**            vars,               /**< variables of the constraint */
562    SCIP_SETPPCTYPE       setppctype          /**< type of constraint: set partitioning, packing, or covering constraint */
563    )
564 {
565    assert(consdata != NULL);
566    assert(nvars == 0 || vars != NULL);
567 
568    SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
569 
570    (*consdata)->signature = 0;
571    (*consdata)->row = NULL;
572    (*consdata)->existmultaggr = FALSE;
573    (*consdata)->catchevents = FALSE;
574    (*consdata)->nfixedzeros = 0;
575    (*consdata)->nfixedones = 0;
576 
577    if( nvars > 0 )
578    {
579       int v;
580 
581       /* @todo the setppc constraint handler does not remove fixed variables from its var array; removing those
582        * variables is only possible if we consider the values of nfixedones and nfixedzeros in all propagation methods
583        */
584 #ifdef SCIP_DISABLED_CODE
585 
586       if( SCIPisConsCompressionEnabled(scip) )
587       {
588          SCIP_VAR** varsbuffer;
589          int k;
590 
591          /* allocate temporary buffer storage for active variables */
592          SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
593 
594          k = 0;
595          /* collect fixed variables to compress the required memory */
596          for( v = 0; v < nvars; ++v )
597          {
598             assert(SCIPvarIsBinary(vars[v]));
599 
600             /* already fixed variables account as fixed ones or zero, only unfixed are appended */
601             if( SCIPvarGetLbGlobal(vars[v]) > 0.5 )
602                (*consdata)->nfixedones++;
603             else if( SCIPvarGetUbGlobal(vars[v]) < 0.5 )
604                (*consdata)->nfixedzeros++;
605             else
606                varsbuffer[k++] = vars[v];
607          }
608 
609          (*consdata)->varssize = k;
610          (*consdata)->nvars = k;
611          /* copy unfixed variables into constraint data */
612          if( k > 0 )
613          {
614             SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
615          }
616 
617          /* free temporary storage */
618          SCIPfreeBufferArray(scip, &varsbuffer);
619       }
620       else
621 #endif
622       {
623          /* for uncompressed copies, simply duplicate the whole array */
624          SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
625          (*consdata)->varssize = nvars;
626          (*consdata)->nvars = nvars;
627       }
628 
629       if( SCIPisTransformed(scip) )
630       {
631          /* get transformed variables */
632          SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
633 
634          /* check for multi-aggregations and capture variables */
635          for( v = 0; v < (*consdata)->nvars; v++ )
636          {
637             SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
638             assert(var != NULL);
639             (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
640             SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
641          }
642       }
643       else
644       {
645          /* capture variables */
646          for( v = 0; v < (*consdata)->nvars; v++ )
647          {
648             assert((*consdata)->vars[v] != NULL);
649             SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
650          }
651       }
652    }
653    else
654    {
655       (*consdata)->vars = NULL;
656       (*consdata)->varssize = 0;
657       (*consdata)->nvars = 0;
658    }
659    (*consdata)->setppctype = setppctype; /*lint !e641*/
660    (*consdata)->sorted = (nvars <= 1);
661    (*consdata)->cliqueadded = FALSE;
662    (*consdata)->validsignature = FALSE;
663    (*consdata)->changed = TRUE;
664    (*consdata)->varsdeleted = FALSE;
665    (*consdata)->merged = FALSE;
666    (*consdata)->presolpropagated = FALSE;
667 
668    return SCIP_OKAY;
669 }
670 
671 /** creates a transformed set partitioning / packing / covering constraint data object */
672 static
consdataCreateTransformed(SCIP * scip,SCIP_CONSDATA ** consdata,int nvars,SCIP_VAR ** vars,SCIP_SETPPCTYPE setppctype)673 SCIP_RETCODE consdataCreateTransformed(
674    SCIP*                 scip,               /**< SCIP data structure */
675    SCIP_CONSDATA**       consdata,           /**< pointer to store the set partitioning / packing / covering constraint */
676    int                   nvars,              /**< number of variables in the constraint */
677    SCIP_VAR**            vars,               /**< variables of the constraint */
678    SCIP_SETPPCTYPE       setppctype          /**< type of constraint: set partitioning, packing, or covering constraint */
679    )
680 {
681    assert(consdata != NULL);
682    assert(nvars == 0 || vars != NULL);
683 
684    /* create constraint data */
685    SCIP_CALL( consdataCreate(scip, consdata, nvars, vars, setppctype) );
686 
687    /* transform the variables */
688    SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
689 
690    return SCIP_OKAY;
691 }
692 
693 /** frees a set partitioning / packing / covering constraint data */
694 static
consdataFree(SCIP * scip,SCIP_CONSDATA ** consdata)695 SCIP_RETCODE consdataFree(
696    SCIP*                 scip,               /**< SCIP data structure */
697    SCIP_CONSDATA**       consdata            /**< pointer to store the set partitioning / packing / covering constraint */
698    )
699 {
700    int v;
701 
702    assert(consdata != NULL);
703    assert(*consdata != NULL);
704 
705    /* release the row */
706    if( (*consdata)->row != NULL )
707    {
708       SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
709    }
710 
711    /* release variables */
712    for( v = 0; v < (*consdata)->nvars; v++ )
713    {
714       assert((*consdata)->vars[v] != NULL);
715       SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
716    }
717 
718    SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->varssize);
719    SCIPfreeBlockMemory(scip, consdata);
720 
721    return SCIP_OKAY;
722 }
723 
724 /** prints set partitioning / packing / covering constraint to file stream */
725 static
consdataPrint(SCIP * scip,SCIP_CONSDATA * consdata,FILE * file)726 SCIP_RETCODE consdataPrint(
727    SCIP*                 scip,               /**< SCIP data structure */
728    SCIP_CONSDATA*        consdata,           /**< set partitioning / packing / covering constraint data */
729    FILE*                 file                /**< output file (or NULL for standard output) */
730    )
731 {
732    assert(consdata != NULL);
733 
734    /* print coefficients */
735    if( consdata->nvars == 0 )
736       SCIPinfoMessage(scip, file, "0 ");
737 
738    /* write linear sum */
739    SCIP_CALL( SCIPwriteVarsLinearsum(scip, file, consdata->vars, NULL, consdata->nvars, TRUE) );
740 
741    /* print right hand side */
742    switch( consdata->setppctype )
743    {
744    case SCIP_SETPPCTYPE_PARTITIONING:
745       SCIPinfoMessage(scip, file, " == 1");
746       break;
747    case SCIP_SETPPCTYPE_PACKING:
748       SCIPinfoMessage(scip, file, " <= 1");
749       break;
750    case SCIP_SETPPCTYPE_COVERING:
751       SCIPinfoMessage(scip, file, " >= 1");
752       break;
753    default:
754       SCIPerrorMessage("unknown setppc type\n");
755       return SCIP_ERROR;
756    }
757 
758    return SCIP_OKAY;
759 }
760 
761 /** returns the bit signature of the given constraint data */
762 static
consdataGetSignature(SCIP_CONSDATA * consdata)763 uint64_t consdataGetSignature(
764    SCIP_CONSDATA*        consdata            /**< set partitioning / packing / covering constraint data */
765    )
766 {
767    assert(consdata != NULL);
768 
769    if( !consdata->validsignature )
770    {
771       int i;
772 
773       consdata->signature = 0;
774       for( i = 0; i < consdata->nvars; ++i )
775          consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(consdata->vars[i]));
776       consdata->validsignature = TRUE;
777    }
778 
779    return consdata->signature;
780 }
781 
782 /** sorts setppc constraint's variables by non-decreasing variable index */
783 static
consdataSort(SCIP_CONSDATA * consdata)784 void consdataSort(
785    SCIP_CONSDATA*        consdata            /**< linear constraint data */
786    )
787 {
788    assert(consdata != NULL);
789 
790    if( !consdata->sorted )
791    {
792       if( consdata->nvars <= 1 )
793 	 consdata->sorted = TRUE;
794       else
795       {
796 	 SCIPsortPtr((void**)consdata->vars, SCIPvarComp, consdata->nvars);
797 	 consdata->sorted = TRUE;
798       }
799    }
800    assert(consdata->sorted);
801 #ifdef SCIP_DEBUG
802    /* check sorting */
803    {
804       int v;
805 
806       for( v = 0; v < consdata->nvars; ++v )
807       {
808          assert(v == consdata->nvars-1 || SCIPvarCompare(consdata->vars[v], consdata->vars[v+1]) <= 0);
809       }
810    }
811 #endif
812 }
813 
814 /** changes the type of a setppc constraint */
815 static
setSetppcType(SCIP * scip,SCIP_CONS * cons,SCIP_SETPPCTYPE setppctype)816 SCIP_RETCODE setSetppcType(
817    SCIP*                 scip,               /**< SCIP data structure */
818    SCIP_CONS*            cons,               /**< setppc constraint */
819    SCIP_SETPPCTYPE       setppctype          /**< new type of constraint */
820    )
821 {
822    SCIP_CONSHDLR* conshdlr;
823    SCIP_CONSHDLRDATA* conshdlrdata;
824    SCIP_CONSDATA* consdata;
825    SCIP_Bool locked;
826    int i;
827 
828    consdata = SCIPconsGetData(cons);
829    assert(consdata != NULL);
830 
831    if( (SCIP_SETPPCTYPE)consdata->setppctype == setppctype )
832       return SCIP_OKAY;
833 
834    SCIPdebugMsg(scip, " -> converting <%s> into setppc type %d\n", SCIPconsGetName(cons), setppctype);
835 
836    /* remove rounding locks */
837    locked = FALSE;
838    for( i = 0; i < NLOCKTYPES && !locked; i++ )
839       locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i);
840 
841    if( locked )
842    {
843       for( i = 0; i < consdata->nvars; ++i )
844       {
845          SCIP_CALL( unlockRounding(scip, cons, consdata->vars[i]) );
846       }
847    }
848 
849    conshdlr = SCIPconsGetHdlr(cons);
850    assert(conshdlr != NULL);
851    conshdlrdata = SCIPconshdlrGetData(conshdlr);
852    assert(conshdlrdata != NULL);
853 
854    if( SCIPisTransformed(scip) )
855    {
856       if( setppctype == SCIP_SETPPCTYPE_PARTITIONING )
857       {
858          ++(conshdlrdata->nsetpart);
859          assert(conshdlrdata->nsetpart >= 0);
860       }
861       else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
862       {
863          --(conshdlrdata->nsetpart);
864          assert(conshdlrdata->nsetpart >= 0);
865       }
866    }
867 
868    /* change the constraint type */
869    consdata->setppctype = setppctype; /*lint !e641*/
870 
871    /* reinstall rounding locks again */
872    if( locked )
873    {
874       for( i = 0; i < consdata->nvars; ++i )
875       {
876          SCIP_CALL( lockRounding(scip, cons, consdata->vars[i]) );
877       }
878    }
879 
880    /* remember that we changed a constraint type for clique lifting procedure */
881    if( setppctype != SCIP_SETPPCTYPE_COVERING )
882       conshdlrdata->updatedsetppctype = TRUE;
883 
884    return SCIP_OKAY;
885 }
886 
887 /** catches events for variable at given position */
888 static
catchEvent(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr,int pos)889 SCIP_RETCODE catchEvent(
890    SCIP*                 scip,               /**< SCIP data structure */
891    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint */
892    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
893    int                   pos                 /**< array position of variable to catch bound change events for */
894    )
895 {
896    SCIP_CONSDATA* consdata;
897    SCIP_EVENTTYPE eventtype;
898    SCIP_VAR* var;
899 
900    consdata = SCIPconsGetData(cons);
901    assert(consdata != NULL);
902    assert(eventhdlr != NULL);
903    assert(0 <= pos && pos < consdata->nvars);
904    assert(consdata->vars != NULL);
905 
906    var = consdata->vars[pos];
907    assert(var != NULL);
908 
909    /* we are catching the following events:
910     *
911     * - SCIP_EVENTTYPE_BOUNDCHANGED: Is used to count the number of variable fixed locally to zero and one. That helps
912     *                                to speed up the propagation
913     *
914     * - SCIP_EVENTTYPE_VARDELETED: Is caught to remove a deleted variable from the constraint
915     *
916     * - SCIP_EVENTTYPE_VARFIXED: Is used to get informed if a variable of the constraint was aggregated which means was
917     *                            detected to be equal or a negated variable of on other variable. in case of a negation
918     *                            this could lead to a redundant constraint if the (other) active variable is also part
919     *                            of the constraint.
920     */
921    eventtype =  SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_VARFIXED;
922 
923    /* catch bound change events on variable */
924    SCIP_CALL( SCIPcatchVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) );
925 
926    /* update the fixed variables counters for this variable */
927    if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
928    {
929       consdata->nfixedzeros++;
930 
931       /* during presolving, we may fix the last unfixed variable or do an aggregation if there are two unfixed variables */
932       if( SCIPconsIsActive(cons) && ((SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE) && (consdata->nfixedzeros >= consdata->nvars - 2)) )
933       {
934          consdata->presolpropagated = FALSE;
935 
936          /* during solving, we only propagate again if there is only one unfixed variable left */
937          if( consdata->nfixedzeros >= consdata->nvars - 1 )
938          {
939             SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
940          }
941       }
942    }
943    else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
944    {
945       consdata->nfixedones++;
946 
947       if( SCIPconsIsActive(cons) )
948       {
949          consdata->presolpropagated = FALSE;
950          SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
951       }
952    }
953 
954    return SCIP_OKAY;
955 }
956 
957 /** drops events for variable at given position */
958 static
dropEvent(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr,int pos)959 SCIP_RETCODE dropEvent(
960    SCIP*                 scip,               /**< SCIP data structure */
961    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint */
962    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
963    int                   pos                 /**< array position of variable to catch bound change events for */
964    )
965 {
966    SCIP_CONSDATA* consdata;
967    SCIP_EVENTTYPE eventtype;
968    SCIP_VAR* var;
969 
970    consdata = SCIPconsGetData(cons);
971    assert(consdata != NULL);
972    assert(eventhdlr != NULL);
973    assert(0 <= pos && pos < consdata->nvars);
974    assert(consdata->vars != NULL);
975 
976    var = consdata->vars[pos];
977    assert(var != NULL);
978 
979    eventtype =  SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_VARFIXED;
980 
981    /* drop events on variable */
982    SCIP_CALL( SCIPdropVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, -1) );
983 
984    /* update the fixed variables counters for this variable */
985    if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
986       consdata->nfixedzeros--;
987    else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
988       consdata->nfixedones--;
989 
990    return SCIP_OKAY;
991 }
992 
993 /** catches bound change events for all variables in transformed setppc constraint */
994 static
catchAllEvents(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr)995 SCIP_RETCODE catchAllEvents(
996    SCIP*                 scip,               /**< SCIP data structure */
997    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint */
998    SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
999    )
1000 {
1001    SCIP_CONSDATA* consdata;
1002    int i;
1003 
1004    consdata = SCIPconsGetData(cons);
1005    assert(consdata != NULL);
1006 
1007    if( consdata->catchevents == TRUE )
1008       return SCIP_OKAY;
1009 
1010    /* catch event for every single variable */
1011    for( i = 0; i < consdata->nvars; ++i )
1012    {
1013       SCIP_CALL( catchEvent(scip, cons, eventhdlr, i) );
1014    }
1015 
1016    consdata->catchevents = TRUE;
1017 
1018    return SCIP_OKAY;
1019 }
1020 
1021 /** drops bound change events for all variables in transformed setppc constraint */
1022 static
dropAllEvents(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr)1023 SCIP_RETCODE dropAllEvents(
1024    SCIP*                 scip,               /**< SCIP data structure */
1025    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint */
1026    SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
1027    )
1028 {
1029    SCIP_CONSDATA* consdata;
1030    int i;
1031 
1032    consdata = SCIPconsGetData(cons);
1033    assert(consdata != NULL);
1034 
1035    if( consdata->catchevents == FALSE )
1036       return SCIP_OKAY;
1037 
1038    /* drop event of every single variable */
1039    for( i = 0; i < consdata->nvars; ++i )
1040    {
1041       SCIP_CALL( dropEvent(scip, cons, eventhdlr, i) );
1042    }
1043 
1044    consdata->catchevents = FALSE;
1045 
1046    return SCIP_OKAY;
1047 }
1048 
1049 /** adds coefficient in setppc constraint */
1050 static
addCoef(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)1051 SCIP_RETCODE addCoef(
1052    SCIP*                 scip,               /**< SCIP data structure */
1053    SCIP_CONS*            cons,               /**< setppc constraint */
1054    SCIP_VAR*             var                 /**< variable to add to the constraint */
1055    )
1056 {
1057    SCIP_CONSDATA* consdata;
1058    SCIP_Bool transformed;
1059 
1060    assert(var != NULL);
1061 
1062    consdata = SCIPconsGetData(cons);
1063    assert(consdata != NULL);
1064 
1065    /* are we in the transformed problem? */
1066    transformed = SCIPconsIsTransformed(cons);
1067 
1068    /* always use transformed variables in transformed constraints */
1069    if( transformed )
1070    {
1071       SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1072    }
1073    assert(var != NULL);
1074    assert(transformed == SCIPvarIsTransformed(var));
1075 
1076    SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
1077    consdata->vars[consdata->nvars] = var;
1078    consdata->nvars++;
1079    if( consdata->validsignature )
1080       consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(var));
1081    consdata->sorted = (consdata->nvars == 1);
1082    consdata->changed = TRUE;
1083 
1084    /* capture the variable */
1085    SCIP_CALL( SCIPcaptureVar(scip, var) );
1086 
1087    /* if we are in transformed problem, catch the variable's events */
1088    if( transformed )
1089    {
1090       SCIP_CONSHDLR* conshdlr;
1091       SCIP_CONSHDLRDATA* conshdlrdata;
1092 
1093       /* get event handler */
1094       conshdlr = SCIPconsGetHdlr(cons);
1095       assert(conshdlr != NULL);
1096       conshdlrdata = SCIPconshdlrGetData(conshdlr);
1097       assert(conshdlrdata != NULL);
1098       assert(conshdlrdata->eventhdlr != NULL);
1099 
1100       /* catch bound change events of variable */
1101       if( consdata->catchevents )
1102       {
1103          SCIP_CALL( catchEvent(scip, cons, conshdlrdata->eventhdlr, consdata->nvars-1) );
1104       }
1105 
1106       if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
1107          consdata->existmultaggr = TRUE;
1108 
1109 #ifdef VARUSES
1110       /* if the constraint is currently active, increase the variable usage counter */
1111       if( SCIPconsIsActive(cons) )
1112       {
1113          SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) );
1114       }
1115 #endif
1116    }
1117 
1118    /* install the rounding locks for the new variable */
1119    SCIP_CALL( lockRounding(scip, cons, var) );
1120 
1121    /* add the new coefficient to the LP row */
1122    if( consdata->row != NULL )
1123    {
1124       SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, 1.0) );
1125    }
1126 
1127    consdata->merged = FALSE;
1128    consdata->cliqueadded = FALSE;
1129 
1130    return SCIP_OKAY;
1131 }
1132 
1133 /** deletes coefficient at given position from setppc constraint data */
1134 static
delCoefPos(SCIP * scip,SCIP_CONS * cons,int pos)1135 SCIP_RETCODE delCoefPos(
1136    SCIP*                 scip,               /**< SCIP data structure */
1137    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint */
1138    int                   pos                 /**< position of coefficient to delete */
1139    )
1140 {
1141    SCIP_CONSDATA* consdata;
1142    SCIP_VAR* var;
1143 
1144    assert(scip != NULL);
1145    assert(cons != NULL);
1146 
1147    consdata = SCIPconsGetData(cons);
1148    assert(consdata != NULL);
1149    assert(0 <= pos && pos < consdata->nvars);
1150 
1151    var = consdata->vars[pos];
1152    assert(var != NULL);
1153    assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1154 
1155    /* remove the rounding locks for the deleted variable */
1156    SCIP_CALL( unlockRounding(scip, cons, var) );
1157 
1158    /* if we are in transformed problem, delete the event data of the variable */
1159    if( SCIPconsIsTransformed(cons) )
1160    {
1161       SCIP_CONSHDLR* conshdlr;
1162       SCIP_CONSHDLRDATA* conshdlrdata;
1163 
1164       /* get event handler */
1165       conshdlr = SCIPconsGetHdlr(cons);
1166       conshdlrdata = SCIPconshdlrGetData(conshdlr);
1167       assert(conshdlrdata != NULL);
1168       assert(conshdlrdata->eventhdlr != NULL);
1169 
1170       /* drop bound change events of variable */
1171       if( consdata->catchevents )
1172       {
1173          SCIP_CALL( dropEvent(scip, cons, conshdlrdata->eventhdlr, pos) );
1174       }
1175 
1176       /* the last variable of the constraint was deleted; mark it for propagation (so that it can be deleted) */
1177       if( consdata->nvars == 1 )
1178       {
1179          consdata->presolpropagated = FALSE;
1180       }
1181    }
1182 
1183    /* delete coefficient from the LP row */
1184    if( consdata->row != NULL )
1185    {
1186       SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -1.0) );
1187    }
1188 
1189    /* move the last variable to the free slot */
1190    if( pos != consdata->nvars - 1 )
1191    {
1192       consdata->vars[pos] = consdata->vars[consdata->nvars-1];
1193       consdata->sorted = FALSE;
1194    }
1195    consdata->nvars--;
1196    consdata->validsignature = FALSE;
1197    consdata->changed = TRUE;
1198 
1199    /* release variable */
1200    SCIP_CALL( SCIPreleaseVar(scip, &var) );
1201 
1202    return SCIP_OKAY;
1203 }
1204 
1205 /** in case a part (more than one variable) in the setppc constraint is independent of every else (is locked only by
1206  *  this constraint), we can perform dual reductions;
1207  *
1208  *  (1) set covering
1209  *
1210  *      - fix all independent variables with negative object coefficient to one
1211  *      - fix all remaining independent variables to zero
1212  *
1213  *      (i) all variables are independent and the constraint is not modifiable
1214  *
1215  *          - fix the variable with the smallest object coefficient to one
1216  *
1217  *     (ii) a variable x has exactly 0 uplocks and arbitrary downlocks and a variable y has exactly 1 downlock and
1218  *          arbitrary uplocks and obj(x) <= obj(y) and obj(y) >= 0
1219  *
1220  *          - fix y to 0, because it is dominated by x
1221  *
1222  *  (2) set partitioning
1223  *
1224  *      (i) all variables are independent and the constraint is not modifiable
1225  *
1226  *          - fix the variable with the smallest object coefficient to one
1227  *          - fix all remaining independent variables to zero
1228  *
1229  *     (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 1 downlock and
1230  *          arbitrary uplocks and obj(x) <= obj(y)
1231  *
1232  *          - fix y to 0, because it is dominated by x
1233  *
1234  *  (3) set packing
1235  *
1236  *      (i) all variables are independent and the constraint is not modifiable
1237  *
1238  *          - fix the variable with the smallest object coefficient to one if the object coefficient is negative or zero
1239  *          - fix all remaining independent variables to zero
1240  *
1241  *     (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 0 downlocks and
1242  *          arbitrary uplocks and obj(x) <= obj(y)
1243  *
1244  *          - fix y to 0, because it is dominated by x
1245  *
1246  *
1247  * Note: the following dual reduction for set covering and set packing constraints is already performed by the presolver
1248  *       "dualfix"
1249  *       (1) in case of a set covering constraint the following dual reduction can be performed:
1250  *           - if a variable in a set covering constraint is only locked by that constraint and has negative or zero
1251  *             objective coefficient than it can be fixed to one
1252  *       (2) in case of a set packing constraint the following dual reduction can be performed:
1253  *           - if a variable in a set packing constraint is only locked by that constraint and has positive or zero
1254  *             objective coefficient than it can be fixed to zero
1255  *
1256  * Note: all dual reduction (ii) could also be performed by the "domcol" presolver, but cause the pairwise comparison of
1257  *       columns is only done heuristically (and here it should be even cheaper) we perform them here (too)
1258  *
1259  */
1260 static
dualPresolving(SCIP * scip,SCIP_CONS * cons,int * nfixedvars,int * ndelconss,SCIP_RESULT * result)1261 SCIP_RETCODE dualPresolving(
1262    SCIP*                 scip,               /**< SCIP data structure */
1263    SCIP_CONS*            cons,               /**< setppc constraint */
1264    int*                  nfixedvars,         /**< pointer to count number of fixings */
1265    int*                  ndelconss,          /**< pointer to count number of deleted constraints  */
1266    SCIP_RESULT*          result              /**< pointer to store the result SCIP_SUCCESS, if presolving was performed */
1267    )
1268 {
1269    SCIP_CONSDATA* consdata;
1270    SCIP_SETPPCTYPE setppctype;
1271    SCIP_VAR** vars;
1272    SCIP_VAR* activevar;
1273    SCIP_VAR* var;
1274    SCIP_Real bestobjval;
1275    SCIP_Real objval;
1276    SCIP_Real fixval;
1277    SCIP_Bool infeasible;
1278    SCIP_Bool fixed;
1279    SCIP_Bool negated;
1280    int noldfixed;
1281    int nposfixings;
1282    int nlockdowns;
1283    int nlockups;
1284    int nvars;
1285    int idx;
1286    int v;
1287 
1288    assert(scip != NULL);
1289    assert(cons != NULL);
1290    assert(nfixedvars != NULL);
1291    assert(ndelconss != NULL);
1292    assert(result != NULL);
1293 
1294    /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
1295     * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
1296     * added to the problems have the check flag set to FALSE
1297     */
1298    if( !SCIPconsIsChecked(cons) )
1299       return SCIP_OKAY;
1300 
1301    assert(SCIPconsIsActive(cons));
1302 
1303    consdata = SCIPconsGetData(cons);
1304    assert(consdata != NULL);
1305 
1306    /* modifiable non-covering constraints cannot be deleted if one variable is fixed to one, because the propagation for
1307     * newly inserted variables must be considered later
1308     */
1309    if( consdata->nfixedones == 1 && SCIPconsIsModifiable(cons) )
1310       return SCIP_OKAY;
1311 
1312    /* all fixed variables should be removed at that point */
1313    assert(consdata->nfixedones == 0);
1314    assert(consdata->nfixedzeros == 0);
1315 
1316    nvars = consdata->nvars;
1317 
1318    /* we don't want to consider small constraints (note that the constraints can be modifiable, so we can't delete this
1319     * constraint)
1320     */
1321    if( nvars < 2 )
1322       return SCIP_OKAY;
1323 
1324    setppctype = (SCIP_SETPPCTYPE)consdata->setppctype;
1325    vars = consdata->vars;
1326    idx = -1;
1327    bestobjval = SCIP_INVALID;
1328 
1329    /* collect the rounding locks depending on the setppc type */
1330    switch( setppctype )
1331    {
1332    case SCIP_SETPPCTYPE_PARTITIONING:
1333       nlockdowns = 1;
1334       nlockups = 1;
1335       break;
1336    case SCIP_SETPPCTYPE_PACKING:
1337       nlockdowns = 0;
1338       nlockups = 1;
1339       break;
1340    case SCIP_SETPPCTYPE_COVERING:
1341       nlockdowns = 1;
1342       nlockups = 0;
1343       break;
1344    default:
1345       SCIPerrorMessage("unknown setppc type\n");
1346       SCIPABORT();
1347       return SCIP_INVALIDDATA; /*lint !e527*/
1348    }
1349 
1350    nposfixings = 0;
1351 
1352    /* check if we can apply the dual reduction; therefore count the number of variables where the setppc has the only
1353     * locks on this constraint
1354     */
1355    for( v = 0; v < nvars; ++v )
1356    {
1357       var = vars[v];
1358       assert(var != NULL);
1359 
1360       /* the variable should not be (globally) fixed */
1361       assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
1362 
1363       if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) >= nlockdowns
1364          && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == nlockups )
1365       {
1366          activevar = var;
1367          negated = FALSE;
1368 
1369          /* get the active variable */
1370          SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1371          assert(SCIPvarIsActive(activevar));
1372 
1373          if( negated )
1374             objval = -SCIPvarGetObj(activevar);
1375          else
1376             objval = SCIPvarGetObj(activevar);
1377 
1378          /* check if the current variable has a smaller objective coefficient */
1379          if( idx == -1 || objval < bestobjval )
1380          {
1381             idx = v;
1382             bestobjval = objval;
1383          }
1384       }
1385 
1386       /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1387        * variables
1388        */
1389       if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1390          && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1391          ++nposfixings;
1392    }
1393 
1394    if( idx == -1 || nposfixings == 0 )
1395       return SCIP_OKAY;
1396 
1397    SCIPdebugMsg(scip, "dual fixing constraint: \n");
1398    SCIPdebug( SCIP_CALL( SCIPprintCons(scip, cons, NULL) ) );
1399    SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") );
1400 
1401    assert(idx >= 0 && idx < nvars);
1402    assert(bestobjval < SCIPinfinity(scip));
1403 
1404    noldfixed = *nfixedvars;
1405 
1406    /* in case of set packing and set partitioning we fix the dominated variables to zero */
1407    if( setppctype != SCIP_SETPPCTYPE_COVERING )
1408    {
1409       /* first part of all variables */
1410       for( v = nvars - 1; v >= 0; --v )
1411       {
1412          if( v == idx )
1413             continue;
1414 
1415          var = vars[v];
1416          assert(var != NULL);
1417 
1418          /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1419           * variables
1420           */
1421          if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1422             && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1423          {
1424             activevar = var;
1425             negated = FALSE;
1426 
1427             /* get the active variable */
1428             SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1429             assert(SCIPvarIsActive(activevar));
1430 
1431             if( negated )
1432                objval = -SCIPvarGetObj(activevar);
1433             else
1434                objval = SCIPvarGetObj(activevar);
1435 
1436             if( objval >= bestobjval )
1437             {
1438                SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
1439                assert(!infeasible);
1440                assert(fixed);
1441 
1442                SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == 0.0\n", SCIPvarGetName(var));
1443                ++(*nfixedvars);
1444             }
1445          }
1446       }
1447    }
1448    /* if we got a set covering constraint and not all variables are locked from this constraint it might not get
1449     * redundant (which is case if it is not possible to fix at least one variable to one), we fix all redundant
1450     * variables to their best bound
1451     */
1452    else
1453    {
1454       /* first part of all variables */
1455       for( v = nvars - 1; v >= 0; --v )
1456       {
1457          if( v == idx )
1458             continue;
1459 
1460          var = vars[v];
1461          assert(var != NULL);
1462 
1463          /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1464           * variables
1465           */
1466          if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1467             && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1468          {
1469             activevar = var;
1470             negated = FALSE;
1471 
1472             /* get the active variable */
1473             SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1474             assert(SCIPvarIsActive(activevar));
1475             assert(negated
1476                || (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksDownType(activevar, SCIP_LOCKTYPE_MODEL)
1477                   && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksUpType(activevar, SCIP_LOCKTYPE_MODEL)));
1478             assert(!negated
1479                || (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksUpType(activevar, SCIP_LOCKTYPE_MODEL)
1480                   && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksDownType(activevar, SCIP_LOCKTYPE_MODEL)));
1481 
1482             if( negated )
1483                objval = -SCIPvarGetObj(activevar);
1484             else
1485                objval = SCIPvarGetObj(activevar);
1486 
1487             if( objval > 0.0 )
1488                fixval = 0.0;
1489             else
1490                fixval = 1.0;
1491 
1492             /* if variables has a negative objective contribution, and is uplocked by another constraint we cannot fix
1493              * the variables to 1
1494              */
1495             if( (fixval == 1.0 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > nlockups) || objval < bestobjval )
1496                continue;
1497 
1498             SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeasible, &fixed) );
1499             assert(!infeasible);
1500             assert(fixed);
1501 
1502             SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == %g\n", SCIPvarGetName(var), fixval);
1503             ++(*nfixedvars);
1504          }
1505       }
1506    }
1507 
1508    /* if all variables but the domination variable is fixed and the constraint is not modifiable or the constraint is a
1509     * covering constraint and the bestobjval is less than or equal to zero, we can fix the domination variable (with best
1510     * objective coefficient) and the constraint gets redundant
1511     */
1512    if( ((*nfixedvars - noldfixed == nvars - 1) && !SCIPconsIsModifiable(cons)) || (setppctype == SCIP_SETPPCTYPE_COVERING && bestobjval <= 0.0) )
1513    {
1514       /* in case of a set packing constraint with positive objective values, all variables can be fixed to zero; in all
1515        * other cases the variable with the smallest objective values is fixed to one
1516        */
1517       if( (setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0
1518          && SCIPvarGetNLocksDownType(vars[idx], SCIP_LOCKTYPE_MODEL) == 0)
1519          || setppctype != SCIP_SETPPCTYPE_PACKING || bestobjval <= 0.0 )
1520       {
1521          if( setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0 )
1522             fixval = 0.0;
1523          else
1524             fixval = 1.0;
1525 
1526          SCIP_CALL( SCIPfixVar(scip, vars[idx], fixval, &infeasible, &fixed) );
1527          assert(!infeasible);
1528          assert(fixed);
1529 
1530          SCIPdebugMsg(scip, " -> dual-fixed best variable <%s> == %g\n", SCIPvarGetName(vars[idx]), fixval);
1531          ++(*nfixedvars);
1532       }
1533 
1534       /* check that we really have a non-violated constraint in hand before deleting */
1535       assert((setppctype == SCIP_SETPPCTYPE_PACKING && consdata->nfixedones <= 1) ||
1536          (setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedones == 1) ||
1537          (setppctype == SCIP_SETPPCTYPE_COVERING && consdata->nfixedones >= 1));
1538 
1539       /* remove constraint since it is redundant */
1540       SCIP_CALL( SCIPdelCons(scip, cons) );
1541       ++(*ndelconss);
1542    }
1543 
1544    assert(*nfixedvars >= noldfixed);
1545 
1546    /* set result pointer to SCIP_SUCCESS, if variables could be fixed */
1547    if( *nfixedvars != noldfixed )
1548       *result = SCIP_SUCCESS;
1549 
1550    return SCIP_OKAY;
1551 }
1552 
1553 /** find pairs of negated variables in constraint:
1554  *  partitioning/packing: all other variables must be zero, constraint is redundant
1555  *  covering: constraint is redundant
1556  *
1557  *  find sets of equal variables in constraint:
1558  *  partitioning/packing: variable must be zero
1559  *  covering: multiple entries of variable can be replaced by single entry
1560  */
1561 static
mergeMultiples(SCIP * scip,SCIP_CONS * cons,int * nfixedvars,int * ndelconss,int * nchgcoefs,SCIP_Bool * cutoff)1562 SCIP_RETCODE mergeMultiples(
1563    SCIP*                 scip,               /**< SCIP data structure */
1564    SCIP_CONS*            cons,               /**< knapsack constraint */
1565    int*                  nfixedvars,         /**< pointer to store number of fixed variables */
1566    int*                  ndelconss,          /**< pointer to store number of deleted constraints */
1567    int*                  nchgcoefs,          /**< pointer to store number of changed coefficients */
1568    SCIP_Bool*            cutoff              /**< pointer to store whether a fixing leads to a cutoff */
1569    )
1570 {
1571    SCIP_CONSDATA* consdata;
1572    int v;
1573 
1574    assert(scip != NULL);
1575    assert(cons != NULL);
1576    assert(nfixedvars != NULL);
1577    assert(ndelconss != NULL);
1578    assert(nchgcoefs != NULL);
1579    assert(cutoff != NULL);
1580 
1581    consdata = SCIPconsGetData(cons);
1582    assert(consdata != NULL);
1583 
1584    if( consdata->merged || SCIPconsIsDeleted(cons) )
1585       return SCIP_OKAY;
1586 
1587    if( consdata->nvars <= 1 )
1588    {
1589       consdata->merged = TRUE;
1590       return SCIP_OKAY;
1591    }
1592 
1593    assert(consdata->vars != NULL || consdata->nvars == 0);
1594 
1595    /* sorting array after indices of variables, that's only for faster merging */
1596    SCIPsortPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, consdata->nvars);
1597    /* setppc sorting now lost */
1598    consdata->sorted = FALSE;
1599 
1600    /* loop backwards through the items: deletion only affects rear items */
1601    for( v = consdata->nvars - 1; v > 0; --v )
1602    {
1603       SCIP_VAR* var1;
1604       SCIP_VAR* var2;
1605       SCIP_Bool negated1;
1606       SCIP_Bool negated2;
1607 
1608       negated1 = FALSE;
1609       negated2 = FALSE;
1610 
1611       var1 = consdata->vars[v];
1612       assert(SCIPvarIsBinary(var1));
1613       assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_FIXED);
1614       if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED )
1615       {
1616          var1 = SCIPvarGetNegatedVar(var1);
1617          negated1 = TRUE;
1618       }
1619       assert(var1 != NULL);
1620 
1621       var2 = consdata->vars[v-1];
1622       assert(SCIPvarIsBinary(var2));
1623       assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_FIXED);
1624       if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED )
1625       {
1626          var2 = SCIPvarGetNegatedVar(var2);
1627          negated2 = TRUE;
1628       }
1629       assert(var2 != NULL);
1630 
1631       if( var1 == var2 )
1632       {
1633          SCIP_Bool infeasible;
1634          SCIP_Bool fixed;
1635 
1636          /* one variables is active and the other is the same negated variable */
1637          if( negated1 != negated2  )
1638          {
1639             /* all other variable have to be zero if it's a partitioning or packing constraint */
1640             if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
1641             {
1642                int i;
1643 
1644                assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
1645                   || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
1646 
1647                for( i = consdata->nvars - 1; i >= 0; --i )
1648                   if( i != v && i != (v-1) )
1649                   {
1650                      SCIP_CALL( SCIPfixVar(scip, consdata->vars[i], 0.0, &infeasible, &fixed) );
1651                      if( infeasible )
1652                      {
1653                         SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
1654                            SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]));
1655                         *cutoff = TRUE;
1656                         return SCIP_OKAY;
1657                      }
1658 
1659                      if( fixed )
1660 			++(*nfixedvars);
1661                   }
1662             }
1663             /* all setppc-type constraints are redundant */
1664             SCIP_CALL( SCIPdelCons(scip, cons) );
1665             ++(*ndelconss);
1666             return SCIP_OKAY;
1667          }
1668          /* both variables are either active or negated */
1669          else
1670          {
1671             /* this variable can be fixed to zero if it's a partitioning or packing constraint */
1672             if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
1673             {
1674                assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
1675                   || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
1676 
1677                SCIP_CALL( SCIPfixVar(scip, var1, negated1 ? 1.0 : 0.0, &infeasible, &fixed) );
1678                if( infeasible )
1679                {
1680                   SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == %g\n",
1681                      SCIPconsGetName(cons), SCIPvarGetName(var1), negated1 ? 1.0 : 0.0);
1682                   *cutoff = TRUE;
1683                   return SCIP_OKAY;
1684                }
1685 
1686                if( fixed )
1687 		  ++(*nfixedvars);
1688             }
1689             /* multiple entries of variable can be replaced by single entry */
1690             else
1691             {
1692                SCIP_CALL( delCoefPos(scip, cons, v) ); /* only some changed behind position v-1, so it's okay */
1693                ++(*nchgcoefs);
1694             }
1695          }
1696          consdata->changed = TRUE;
1697       }
1698    }
1699    consdata->merged = TRUE;
1700 
1701    return SCIP_OKAY;
1702 }
1703 
1704 /** deletes all zero-fixed variables and replace aggregated variables */
1705 static
applyFixings(SCIP * scip,SCIP_CONS * cons,int * naddconss,int * ndelconss,int * nfixedvars,SCIP_Bool * cutoff)1706 SCIP_RETCODE applyFixings(
1707    SCIP*                 scip,               /**< SCIP data structure */
1708    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint */
1709    int*                  naddconss,          /**< pointer to count number of added constraints, or NULL indicating we
1710                                               *   can not resolve multi-aggregations
1711                                               */
1712    int*                  ndelconss,          /**< pointer to count number of deleted constraints, or NULL indicating we
1713                                               *   can not resolve multi-aggregations
1714                                               */
1715    int*                  nfixedvars,         /**< pointer to store number of fixed variables, or NULL indicating we can
1716                                               *   not resolve multi-aggregations
1717                                               */
1718    SCIP_Bool*            cutoff              /**< pointer to store whether a fixing leads to a cutoff, or NULL
1719                                               *   indicating we can not resolve multi-aggregations
1720                                               */
1721    )
1722 {
1723    SCIP_CONSDATA* consdata;
1724    int v;
1725 
1726    assert(scip != NULL);
1727    assert(cons != NULL);
1728 
1729    consdata = SCIPconsGetData(cons);
1730    assert(consdata != NULL);
1731 
1732    /* all multi-aggregations should be resolved */
1733    consdata->existmultaggr = FALSE;
1734 
1735    v = 0;
1736    while( v < consdata->nvars )
1737    {
1738       SCIP_VAR* var;
1739 
1740       var = consdata->vars[v];
1741       assert(SCIPvarIsBinary(var));
1742 
1743       if( SCIPvarGetUbGlobal(var) < 0.5 )
1744       {
1745          assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
1746          SCIP_CALL( delCoefPos(scip, cons, v) );
1747       }
1748       else
1749       {
1750          SCIP_VAR* repvar;
1751          SCIP_Bool negated;
1752 
1753          /* get binary representative of variable */
1754          SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
1755 
1756          /* resolve multi-aggregation */
1757          if( SCIPvarGetStatus(repvar) == SCIP_VARSTATUS_MULTAGGR || (SCIPvarGetStatus(repvar) == SCIP_VARSTATUS_NEGATED && SCIPvarGetStatus(SCIPvarGetNegatedVar(repvar)) == SCIP_VARSTATUS_MULTAGGR) )
1758          {
1759             SCIP_VAR** consvars;
1760             SCIP_Real* consvals;
1761             SCIP_Real constant = 0.0;
1762             SCIP_Bool easycase;
1763             int nconsvars;
1764             int requiredsize;
1765             int v2;
1766 
1767             nconsvars = 1;
1768             SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 1) );
1769             SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 1) );
1770             consvars[0] = repvar;
1771             consvals[0] = 1.0;
1772 
1773             /* get active variables for new constraint */
1774             SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) );
1775             /* if space was not enough we need to resize the buffers */
1776             if( requiredsize > nconsvars )
1777             {
1778                SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1779                SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1780 
1781                SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
1782                assert(requiredsize <= nconsvars);
1783             }
1784 
1785             easycase = FALSE;
1786 
1787             if( SCIPisZero(scip, constant) )
1788             {
1789                /* add active representation */
1790                for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1791                {
1792                   if( !SCIPvarIsBinary(consvars[v2]) )
1793                      break;
1794 
1795                   if( !SCIPisEQ(scip, consvals[v2], 1.0) )
1796                      break;
1797                }
1798 
1799                if( v2 < 0 )
1800                   easycase = TRUE;
1801             }
1802             else if( SCIPisFeasEQ(scip, constant, 1.0) )
1803             {
1804                /* check for another multi-aggregation */
1805                for( v2 = consdata->nvars - 1; v2 > v; --v2 )
1806                {
1807                   if( SCIPvarGetStatus(SCIPvarGetProbvar(consdata->vars[v])) == SCIP_VARSTATUS_MULTAGGR )
1808                      break;
1809                }
1810 
1811                /* constraint is redundant */
1812                if( v2 == v && nconsvars == 0 )
1813                {
1814                   /* we can fix */
1815                   if( consdata->nvars > 1 && (SCIP_SETPPCTYPE)consdata->setppctype != SCIP_SETPPCTYPE_COVERING )
1816                   {
1817                      if( nfixedvars != NULL )
1818                      {
1819                         SCIP_Bool fixed;
1820 
1821                         assert(cutoff != NULL);
1822 
1823                         for( v2 = consdata->nvars - 1; v2 >= 0; --v2 )
1824                         {
1825                            if( consdata->vars[v2] != var )
1826                            {
1827                               SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(consdata->vars[v2]));
1828 
1829                               /* fix all remaining variables to zero, constraint is already feasible or infeasible */
1830                               SCIP_CALL( SCIPfixVar(scip, consdata->vars[v2], 0.0, cutoff, &fixed) );
1831                               if( *cutoff )
1832                               {
1833                                  SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
1834                                     SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v2]));
1835 
1836                                  SCIPfreeBufferArray(scip, &consvals);
1837                                  SCIPfreeBufferArray(scip, &consvars);
1838 
1839                                  goto TERMINATE;
1840                               }
1841 
1842                               if( fixed )
1843                                  ++(*nfixedvars);
1844                            }
1845                         }
1846                      }
1847                   }
1848 
1849                   if( ndelconss != NULL && (nfixedvars != NULL || consdata->nvars == 1 || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING) )
1850                   {
1851                      /* delete old constraint */
1852                      SCIP_CALL( SCIPdelCons(scip, cons) );
1853                      ++(*ndelconss);
1854                   }
1855                   SCIPfreeBufferArray(scip, &consvals);
1856                   SCIPfreeBufferArray(scip, &consvars);
1857 
1858                   goto TERMINATE;
1859                }
1860             }
1861 
1862             /* we can easily add the coefficients and still have a setppc constraint */
1863             if( easycase )
1864             {
1865                /* delete old (multi-aggregated) variable */
1866                SCIP_CALL( delCoefPos(scip, cons, v) );
1867 
1868                /* add active representation */
1869                for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1870                {
1871                   assert(SCIPvarIsBinary(consvars[v2]));
1872                   assert(SCIPvarIsActive(consvars[v2]) || (SCIPvarGetStatus(consvars[v2]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(consvars[v2]))));
1873 
1874                   SCIP_CALL( addCoef(scip, cons, consvars[v2]) );
1875                }
1876             }
1877             /* we need to degrade this setppc constraint to a linear constraint */
1878             else if( (ndelconss != NULL && naddconss != NULL) || SCIPconsIsAdded(cons) )
1879             {
1880                char name[SCIP_MAXSTRLEN];
1881                SCIP_CONS* newcons;
1882                SCIP_Real lhs;
1883                SCIP_Real rhs;
1884                int size;
1885                int k;
1886 
1887                /* it might happen that there are more than one multi-aggregated variable, so we need to get the whole
1888                 * probvar sum over all variables
1889                 */
1890 
1891                size = MAX(nconsvars, 1) + consdata->nvars - 1;
1892 
1893                /* memory needed is at least old number of variables - 1 + number of variables in first multi-aggregation */
1894                SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, size) );
1895                SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, size) );
1896 
1897                nconsvars = consdata->nvars;
1898 
1899                /* add constraint variables to new linear variables */
1900                for( k = consdata->nvars - 1; k >= 0; --k )
1901                {
1902                   consvars[k] = consdata->vars[k];
1903                   consvals[k] = 1.0;
1904                }
1905 
1906                constant = 0.0;
1907 
1908                /* get active variables for new constraint */
1909                SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize, TRUE) );
1910 
1911                /* if space was not enough (we found another multi-aggregation), we need to resize the buffers */
1912                if( requiredsize > nconsvars )
1913                {
1914                   SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1915                   SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1916 
1917                   SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
1918                   assert(requiredsize <= nconsvars);
1919                }
1920 
1921                /* compute sides */
1922                if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
1923                {
1924                   lhs = -SCIPinfinity(scip);
1925                   rhs = 1.0 - constant;
1926                }
1927                else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
1928                {
1929                   lhs = 1.0 - constant;
1930                   rhs = 1.0 - constant;
1931                }
1932                else
1933                {
1934                   assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING);
1935                   lhs = 1.0 - constant;
1936                   rhs = SCIPinfinity(scip);
1937                }
1938 
1939                /* create linear constraint */
1940                (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
1941                SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, nconsvars, consvars, consvals, lhs, rhs,
1942                   SCIPconsIsInitial(cons),
1943                   SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
1944                   SCIPconsIsPropagated(cons),  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
1945                   SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
1946                SCIP_CALL( SCIPaddCons(scip, newcons) );
1947 
1948                SCIPdebugMsg(scip, "added linear constraint: ");
1949                SCIPdebugPrintCons(scip, newcons, NULL);
1950                SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1951 
1952                SCIPfreeBufferArray(scip, &consvals);
1953                SCIPfreeBufferArray(scip, &consvars);
1954 
1955                /* delete old constraint */
1956                SCIP_CALL( SCIPdelCons(scip, cons) );
1957                if( ndelconss != NULL && naddconss != NULL )
1958                {
1959                   ++(*ndelconss);
1960                   ++(*naddconss);
1961                }
1962 
1963                goto TERMINATE;
1964             }
1965             /* we need to degrade this setppc constraint to a linear constraint*/
1966             else
1967             {
1968                /* check, if the variable should be replaced with the representative */
1969                if( repvar != var )
1970                {
1971                   /* delete old (aggregated) variable */
1972                   SCIP_CALL( delCoefPos(scip, cons, v) );
1973 
1974                   /* add representative instead */
1975                   SCIP_CALL( addCoef(scip, cons, repvar) );
1976                }
1977 
1978                SCIPwarningMessage(scip, "setppc constraint <%s> has a multi-aggregated variable, which was not resolved and therefore could lead to aborts\n", SCIPconsGetName(cons));
1979                ++v;
1980             }
1981 
1982             SCIPfreeBufferArray(scip, &consvals);
1983             SCIPfreeBufferArray(scip, &consvars);
1984          }
1985          else
1986          {
1987             /* check, if the variable should be replaced with the representative */
1988             if( repvar != var )
1989             {
1990                /* delete old (aggregated) variable */
1991                SCIP_CALL( delCoefPos(scip, cons, v) );
1992 
1993                /* add representative instead */
1994                SCIP_CALL( addCoef(scip, cons, repvar) );
1995             }
1996             else
1997                ++v;
1998          }
1999       }
2000    }
2001 
2002  TERMINATE:
2003    /* all multi-aggregations should be resolved */
2004    consdata->existmultaggr = FALSE;
2005 
2006    return SCIP_OKAY;
2007 }
2008 
2009 /** analyzes conflicting assignment on given constraint where all of the variables where assigned to zero,
2010  *  and adds conflict constraint to problem
2011  */
2012 static
analyzeConflictZero(SCIP * scip,SCIP_CONS * cons)2013 SCIP_RETCODE analyzeConflictZero(
2014    SCIP*                 scip,               /**< SCIP data structure */
2015    SCIP_CONS*            cons                /**< set partitioning / packing / covering constraint that detected the conflict */
2016    )
2017 {
2018    SCIP_CONSDATA* consdata;
2019    int v;
2020 
2021    /* conflict analysis can only be applied in solving stage and if it is applicable */
2022    if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
2023       return SCIP_OKAY;
2024 
2025    consdata = SCIPconsGetData(cons);
2026    assert(consdata != NULL);
2027    assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
2028       || consdata->setppctype == SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
2029 
2030    /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
2031    SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
2032 
2033    for( v = 0; v < consdata->nvars; ++v )
2034    {
2035       SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
2036    }
2037 
2038    /* analyze the conflict */
2039    SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2040 
2041    return SCIP_OKAY;
2042 }
2043 
2044 /** analyzes conflicting assignment on given constraint where two of the variables where assigned to one,
2045  *  and adds conflict constraint to problem
2046  */
2047 static
analyzeConflictOne(SCIP * scip,SCIP_CONS * cons)2048 SCIP_RETCODE analyzeConflictOne(
2049    SCIP*                 scip,               /**< SCIP data structure */
2050    SCIP_CONS*            cons                /**< set partitioning / packing / covering constraint that detected the conflict */
2051    )
2052 {
2053    SCIP_CONSDATA* consdata;
2054    int v;
2055    int n;
2056 
2057    /* conflict analysis can only be applied in solving stage and if it is applicable */
2058    if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
2059       return SCIP_OKAY;
2060 
2061    consdata = SCIPconsGetData(cons);
2062    assert(consdata != NULL);
2063    assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
2064       || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2065 
2066    /* initialize conflict analysis, and add the two variables assigned to one to conflict candidate queue */
2067    SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
2068 
2069    n = 0;
2070    for( v = 0; v < consdata->nvars && n < 2; ++v )
2071    {
2072       if( SCIPvarGetLbLocal(consdata->vars[v]) > 0.5 )
2073       {
2074          SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
2075          n++;
2076       }
2077    }
2078    assert(n == 2);
2079 
2080    /* analyze the conflict */
2081    SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2082 
2083    return SCIP_OKAY;
2084 }
2085 
2086 /** checks constraint for violation only looking at the fixed variables, applies further fixings if possible */
2087 static
processFixings(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * nfixedvars,SCIP_Bool * addcut,SCIP_Bool * mustcheck)2088 SCIP_RETCODE processFixings(
2089    SCIP*                 scip,               /**< SCIP data structure */
2090    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint to be processed */
2091    SCIP_Bool*            cutoff,             /**< pointer to store TRUE, if the node can be cut off */
2092    int*                  nfixedvars,         /**< pointer to count number of deleted variables */
2093    SCIP_Bool*            addcut,             /**< pointer to store whether this constraint must be added as a cut */
2094    SCIP_Bool*            mustcheck           /**< pointer to store whether this constraint must be checked for feasibility */
2095    )
2096 {
2097    SCIP_CONSDATA* consdata;
2098 #ifndef NDEBUG
2099    int oldnfixedvars;
2100 #endif
2101 
2102    assert(cons != NULL);
2103    assert(SCIPconsGetHdlr(cons) != NULL);
2104    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2105    assert(cutoff != NULL);
2106    assert(nfixedvars != NULL);
2107    assert(addcut != NULL);
2108    assert(mustcheck != NULL);
2109 
2110 #ifndef NDEBUG
2111    oldnfixedvars = *nfixedvars;
2112 #endif
2113 
2114    consdata = SCIPconsGetData(cons);
2115    assert(consdata != NULL);
2116    assert(consdata->nvars == 0 || consdata->vars != NULL);
2117    assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
2118    assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
2119 
2120    *addcut = FALSE;
2121    *mustcheck = TRUE;
2122 
2123    /*SCIPdebugMsg(scip, "processing constraint <%s> with respect to fixed variables (%d fixed to 0.0, %d fixed to 1.0)\n",
2124      SCIPconsGetName(cons), consdata->nfixedzeros, consdata->nfixedones);*/
2125 
2126    if( consdata->nfixedones == 1 )
2127    {
2128       /* exactly one variable is fixed to 1:
2129        * - a set covering constraint is feasible anyway and can be disabled
2130        * - all other variables in a set partitioning or packing constraint must be zero
2131        */
2132       if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2133       {
2134          SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons));
2135          SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2136       }
2137       else
2138       {
2139          if( consdata->nfixedzeros < consdata->nvars - 1 )
2140          {
2141             SCIP_VAR** vars;
2142             SCIP_VAR* var;
2143 #ifndef NDEBUG
2144             SCIP_Bool fixedonefound;
2145 #endif
2146             SCIP_Bool infeasible;
2147             SCIP_Bool tightened;
2148             int nvars;
2149             int v;
2150             int oneidx = -1;
2151 
2152             SCIPdebugMsg(scip, " -> fixing all other variables to zero in set packing/partitioning constraint <%s>\n",
2153                SCIPconsGetName(cons));
2154 
2155             /* unfixed variables exist: fix them to zero;
2156              * this could result in additional variables fixed to one due to aggregations; in this case, the
2157              * constraint is infeasible in local bounds
2158              */
2159             vars = consdata->vars;
2160             nvars = consdata->nvars;
2161 #ifndef NDEBUG
2162             fixedonefound = FALSE;
2163 #endif
2164             for( v = 0; v < nvars && consdata->nfixedones == 1; ++v )
2165             {
2166                var = vars[v];
2167                assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0));
2168                if( SCIPvarGetLbLocal(var) < 0.5 )
2169                {
2170                   SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, oneidx, &infeasible, &tightened) );
2171                   assert(!infeasible);
2172 
2173                   if( tightened )
2174                      ++(*nfixedvars);
2175 
2176                   SCIPdebugMsg(scip, "   -> fixed <%s> to zero (tightened=%u)\n", SCIPvarGetName(var), tightened);
2177                }
2178                else
2179                {
2180 #ifndef NDEBUG
2181                   fixedonefound = TRUE;
2182 #endif
2183                   oneidx = v;
2184                }
2185             }
2186             /* the fixed to one variable must have been found, and at least one variable must have been fixed */
2187             assert(consdata->nfixedones >= 2 || (fixedonefound && *nfixedvars > oldnfixedvars));
2188 
2189             SCIP_CALL( SCIPresetConsAge(scip, cons) );
2190          }
2191 
2192          /* now all other variables are fixed to zero:
2193           * the constraint is feasible, and if it's not modifiable, it is redundant
2194           */
2195          if( !SCIPconsIsModifiable(cons) && consdata->nfixedones == 1 )
2196          {
2197             SCIPdebugMsg(scip, " -> disabling set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons));
2198             SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2199          }
2200       }
2201       *mustcheck = FALSE;
2202    }
2203 
2204    if( consdata->nfixedones >= 2 )
2205    {
2206       /* at least two variables are fixed to 1:
2207        * - a set covering constraint is feasible anyway and can be disabled
2208        * - a set partitioning or packing constraint is infeasible
2209        */
2210       if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2211       {
2212          SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons));
2213          SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2214       }
2215       else
2216       {
2217          SCIPdebugMsg(scip, " -> conflict on set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons));
2218 
2219          SCIP_CALL( SCIPresetConsAge(scip, cons) );
2220 
2221          /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
2222          SCIP_CALL( analyzeConflictOne(scip, cons) );
2223 
2224          *cutoff = TRUE;
2225       }
2226       *mustcheck = FALSE;
2227    }
2228    else if( consdata->nfixedzeros == consdata->nvars )
2229    {
2230       /* all variables are fixed to zero:
2231        * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled
2232        * - a set partitioning or covering constraint is infeasible, and if it's unmodifiable, the node
2233        *   can be cut off -- otherwise, the constraint must be added as a cut and further pricing must
2234        *   be performed
2235        */
2236       assert(consdata->nfixedones == 0);
2237 
2238       if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/
2239       {
2240          if( !SCIPconsIsModifiable(cons) )
2241          {
2242             SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons));
2243             SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2244          }
2245       }
2246       else
2247       {
2248          SCIPdebugMsg(scip, " -> set covering/partitioning constraint <%s> is infeasible\n", SCIPconsGetName(cons));
2249 
2250          SCIP_CALL( SCIPresetConsAge(scip, cons) );
2251          if( SCIPconsIsModifiable(cons) )
2252             *addcut = TRUE;
2253          else
2254          {
2255             /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
2256             SCIP_CALL( analyzeConflictZero(scip, cons) );
2257 
2258             *cutoff = TRUE;
2259          }
2260       }
2261       *mustcheck = FALSE;
2262    }
2263    else if( consdata->nfixedzeros == consdata->nvars - 1 && consdata->nfixedones == 0 )
2264    {
2265       /* all variables except one are fixed to zero:
2266        * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled
2267        * - an unmodifiable set partitioning or covering constraint is feasible and can be disabled after the
2268        *   remaining variable is fixed to one
2269        * - a modifiable set partitioning or covering constraint must be checked manually
2270        */
2271       if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/
2272       {
2273          if( !SCIPconsIsModifiable(cons) )
2274          {
2275             SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons));
2276             SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2277          }
2278          *mustcheck = FALSE;
2279       }
2280       else if( !SCIPconsIsModifiable(cons) )
2281       {
2282          SCIP_VAR** vars;
2283          SCIP_VAR* var;
2284          SCIP_Bool infeasible;
2285          SCIP_Bool tightened;
2286          int nvars;
2287          int v;
2288 
2289          /* search the single variable that can be fixed */
2290          vars = consdata->vars;
2291          nvars = consdata->nvars;
2292          for( v = 0; v < nvars; ++v )
2293          {
2294             var = vars[v];
2295             assert(SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)));
2296             assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0));
2297             if( SCIPvarGetUbLocal(var) > 0.5 )
2298             {
2299                SCIPdebugMsg(scip, " -> fixing remaining variable <%s> to one in set covering/partitioning constraint <%s>\n",
2300                   SCIPvarGetName(var), SCIPconsGetName(cons));
2301                SCIP_CALL( SCIPinferBinvarCons(scip, var, TRUE, cons, 0, &infeasible, &tightened) );
2302                assert(!infeasible);
2303                assert(tightened);
2304 
2305                ++(*nfixedvars);
2306                break;
2307             }
2308          }
2309          assert(v < nvars);
2310          assert(consdata->nfixedzeros == consdata->nvars - 1);
2311          assert(consdata->nfixedones == 1);
2312 
2313          SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2314          *mustcheck = FALSE;
2315       }
2316    }
2317    assert(consdata->nfixedzeros + consdata->nfixedones <= consdata->nvars);
2318 
2319    return SCIP_OKAY;
2320 }
2321 
2322 /** checks constraint for violation, returns TRUE iff constraint is feasible */
2323 static
checkCons(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_SOL * sol)2324 SCIP_Bool checkCons(
2325    SCIP*                 scip,               /**< SCIP data structure */
2326    SCIP_CONSDATA*        consdata,           /**< set partitioning / packing / covering constraint to be checked */
2327    SCIP_SOL*             sol                 /**< primal CIP solution */
2328    )
2329 {
2330    SCIP_VAR** vars;
2331    SCIP_Real solval;
2332    SCIP_Real sum;
2333    SCIP_Real sumbound;
2334    SCIP_Real absviol;
2335    SCIP_Real relviol;
2336    SCIP_Bool check;
2337    int nvars;
2338    int v;
2339 
2340    /* calculate the constraint's activity */
2341    vars = consdata->vars;
2342    nvars = consdata->nvars;
2343    sum = 0.0;
2344    sumbound = ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING ? 1.0 : 1.0 + 2*SCIPfeastol(scip));
2345    for( v = 0; v < nvars && sum < sumbound; ++v )  /* if sum >= sumbound, the feasibility is clearly decided */
2346    {
2347       assert(SCIPvarIsBinary(vars[v]));
2348 
2349       solval = SCIPgetSolVal(scip, sol, vars[v]);
2350       assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0));
2351 
2352       sum += solval;
2353    }
2354 
2355    absviol = sum - 1.0;
2356    relviol = SCIPrelDiff(sum, 1.0);
2357    switch( consdata->setppctype )
2358    {
2359    case SCIP_SETPPCTYPE_PARTITIONING:
2360       /* in case of partitioning, the violation is equal to the absolute difference between sum and 1 */
2361       absviol = REALABS(absviol);
2362       relviol = REALABS(relviol);
2363       check = SCIPisFeasEQ(scip, sum, 1.0);
2364       break;
2365    case SCIP_SETPPCTYPE_PACKING:
2366       /* in case of packing, the violation is equal to how much sum exceeds 1 */
2367       check = SCIPisFeasLE(scip, sum, 1.0);
2368       break;
2369    case SCIP_SETPPCTYPE_COVERING:
2370       /* in case of covering, the violation is equal to how much 1 exceeds sum */
2371       absviol = -absviol;
2372       relviol = -relviol;
2373       check = SCIPisFeasGE(scip, sum, 1.0);
2374       break;
2375    default:
2376       SCIPerrorMessage("unknown setppc type\n");
2377       SCIPABORT();
2378       return FALSE; /*lint !e527*/
2379    }
2380 
2381    if( sol != NULL )
2382       SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
2383 
2384    return check;
2385 }
2386 
2387 /** creates an LP row in a set partitioning / packing / covering constraint data object */
2388 static
createRow(SCIP * scip,SCIP_CONS * cons)2389 SCIP_RETCODE createRow(
2390    SCIP*                 scip,               /**< SCIP data structure */
2391    SCIP_CONS*            cons                /**< set partitioning / packing / covering constraint */
2392    )
2393 {
2394    SCIP_CONSDATA* consdata;
2395    SCIP_Real lhs;
2396    SCIP_Real rhs;
2397 
2398    consdata = SCIPconsGetData(cons);
2399    assert(consdata != NULL);
2400    assert(consdata->row == NULL);
2401 
2402    switch( consdata->setppctype )
2403    {
2404    case SCIP_SETPPCTYPE_PARTITIONING:
2405       lhs = 1.0;
2406       rhs = 1.0;
2407       break;
2408    case SCIP_SETPPCTYPE_PACKING:
2409       lhs = -SCIPinfinity(scip);
2410       rhs = 1.0;
2411       break;
2412    case SCIP_SETPPCTYPE_COVERING:
2413       lhs = 1.0;
2414       rhs = SCIPinfinity(scip);
2415       break;
2416    default:
2417       SCIPerrorMessage("unknown setppc type\n");
2418       return SCIP_INVALIDDATA;
2419    }
2420 
2421    SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), lhs, rhs,
2422          SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) );
2423 
2424    SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->row, consdata->nvars, consdata->vars, 1.0) );
2425 
2426    return SCIP_OKAY;
2427 }
2428 
2429 /** adds setppc constraint as cut to the LP */
2430 static
addCut(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff)2431 SCIP_RETCODE addCut(
2432    SCIP*                 scip,               /**< SCIP data structure */
2433    SCIP_CONS*            cons,               /**< setppc constraint */
2434    SCIP_Bool*            cutoff              /**< whether a cutoff has been detected */
2435    )
2436 {
2437    SCIP_CONSDATA* consdata;
2438 
2439    assert( cutoff != NULL );
2440    *cutoff = FALSE;
2441 
2442    consdata = SCIPconsGetData(cons);
2443    assert(consdata != NULL);
2444 
2445    if( consdata->row == NULL )
2446    {
2447       /* convert set partitioning constraint data into LP row */
2448       SCIP_CALL( createRow(scip, cons) );
2449    }
2450    assert(consdata->row != NULL);
2451 
2452    /* insert LP row as cut */
2453    if( !SCIProwIsInLP(consdata->row) )
2454    {
2455       SCIPdebugMsg(scip, "adding constraint <%s> as cut to the LP\n", SCIPconsGetName(cons));
2456       SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
2457    }
2458 
2459    return SCIP_OKAY;
2460 }
2461 
2462 /** checks constraint for violation, and adds it as a cut if possible */
2463 static
separateCons(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol,SCIP_Bool lpfeas,SCIP_Bool * cutoff,SCIP_Bool * separated,SCIP_Bool * reduceddom)2464 SCIP_RETCODE separateCons(
2465    SCIP*                 scip,               /**< SCIP data structure */
2466    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint to be separated */
2467    SCIP_SOL*             sol,                /**< primal CIP solution, NULL for current LP solution */
2468    SCIP_Bool             lpfeas,             /**< is the given solution feasible for the current LP ? */
2469    SCIP_Bool*            cutoff,             /**< pointer to store TRUE, if the node can be cut off */
2470    SCIP_Bool*            separated,          /**< pointer to store TRUE, if a cut was found */
2471    SCIP_Bool*            reduceddom          /**< pointer to store TRUE, if a domain reduction was found */
2472    )
2473 {
2474    SCIP_CONSDATA* consdata;
2475    SCIP_Bool addcut;
2476    SCIP_Bool mustcheck;
2477 
2478    assert(cons != NULL);
2479    assert(SCIPconsGetHdlr(cons) != NULL);
2480    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2481    assert(cutoff != NULL);
2482    assert(separated != NULL);
2483    assert(reduceddom != NULL);
2484 
2485    *cutoff = FALSE;
2486 
2487    consdata = SCIPconsGetData(cons);
2488    assert(consdata != NULL);
2489    assert(consdata->nvars == 0 || consdata->vars != NULL);
2490    assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
2491    assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
2492 
2493    /* skip constraints already in the LP */
2494    if( lpfeas && consdata->row != NULL && SCIProwIsInLP(consdata->row) )
2495       return SCIP_OKAY;
2496 
2497    SCIPdebugMsg(scip, "separating constraint <%s>\n", SCIPconsGetName(cons));
2498 
2499    /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
2500    if( lpfeas )
2501    {
2502       int nfixedvars = 0;
2503 
2504       SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) );
2505 
2506       *reduceddom = (nfixedvars > 0);
2507    }
2508    else
2509    {
2510       mustcheck = TRUE;
2511       addcut = FALSE;
2512    }
2513 
2514    if( mustcheck )
2515    {
2516       assert(!addcut);
2517 
2518       /* variable's fixings didn't give us any information -> we have to check the constraint */
2519       if( lpfeas && consdata->row != NULL )
2520       {
2521          SCIP_Real feasibility;
2522 
2523          assert(!SCIProwIsInLP(consdata->row));
2524          feasibility = SCIPgetRowSolFeasibility(scip, consdata->row, sol);
2525          addcut = SCIPisFeasNegative(scip, feasibility);
2526       }
2527       else
2528          addcut = !checkCons(scip, consdata, sol);
2529 
2530       if( !addcut )
2531       {
2532          /* constraint was feasible -> increase age */
2533          SCIP_CALL( SCIPincConsAge(scip, cons) );
2534       }
2535    }
2536 
2537    if( addcut )
2538    {
2539       /* insert LP row as cut */
2540       SCIP_CALL( addCut(scip, cons, cutoff) );
2541       SCIP_CALL( SCIPresetConsAge(scip, cons) );
2542       *separated = TRUE;
2543    }
2544 
2545    return SCIP_OKAY;
2546 }
2547 
2548 /** enforces the pseudo solution on the given constraint */
2549 static
enforcePseudo(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,SCIP_Bool * infeasible,SCIP_Bool * reduceddom,SCIP_Bool * solvelp)2550 SCIP_RETCODE enforcePseudo(
2551    SCIP*                 scip,               /**< SCIP data structure */
2552    SCIP_CONS*            cons,               /**< set partitioning / packing / covering constraint to be separated */
2553    SCIP_Bool*            cutoff,             /**< pointer to store TRUE, if the node can be cut off */
2554    SCIP_Bool*            infeasible,         /**< pointer to store TRUE, if the constraint was infeasible */
2555    SCIP_Bool*            reduceddom,         /**< pointer to store TRUE, if a domain reduction was found */
2556    SCIP_Bool*            solvelp             /**< pointer to store TRUE, if the LP has to be solved */
2557    )
2558 {
2559    SCIP_Bool addcut;
2560    SCIP_Bool mustcheck;
2561    int nfixedvars = 0;
2562 
2563    assert(!SCIPhasCurrentNodeLP(scip));
2564    assert(cons != NULL);
2565    assert(SCIPconsGetHdlr(cons) != NULL);
2566    assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2567    assert(cutoff != NULL);
2568    assert(infeasible != NULL);
2569    assert(reduceddom != NULL);
2570    assert(solvelp != NULL);
2571 
2572    /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
2573    SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) );
2574 
2575    *reduceddom = (nfixedvars > 0);
2576 
2577    if( mustcheck )
2578    {
2579       SCIP_CONSDATA* consdata;
2580 
2581       assert(!addcut);
2582 
2583       consdata = SCIPconsGetData(cons);
2584       assert(consdata != NULL);
2585 
2586       if( checkCons(scip, consdata, NULL) )
2587       {
2588          /* constraint was feasible -> increase age */
2589          SCIP_CALL( SCIPincConsAge(scip, cons) );
2590       }
2591       else
2592       {
2593          /* constraint was infeasible -> reset age */
2594          SCIP_CALL( SCIPresetConsAge(scip, cons) );
2595          *infeasible = TRUE;
2596       }
2597    }
2598 
2599    if( addcut )
2600    {
2601       /* a cut must be added to the LP -> we have to solve the LP immediately */
2602       SCIP_CALL( SCIPresetConsAge(scip, cons) );
2603       *solvelp = TRUE;
2604    }
2605 
2606    return SCIP_OKAY;
2607 }
2608 
2609 /** gets the key of the given element */
2610 static
SCIP_DECL_HASHGETKEY(hashGetKeySetppccons)2611 SCIP_DECL_HASHGETKEY(hashGetKeySetppccons)
2612 {  /*lint --e{715}*/
2613    /* the key is the element itself */
2614    return elem;
2615 }
2616 
2617 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */
2618 static
SCIP_DECL_HASHKEYEQ(hashKeyEqSetppccons)2619 SCIP_DECL_HASHKEYEQ(hashKeyEqSetppccons)
2620 {
2621 #ifndef NDEBUG
2622    SCIP* scip;
2623 #endif
2624    SCIP_CONSDATA* consdata1;
2625    SCIP_CONSDATA* consdata2;
2626    SCIP_Bool coefsequal;
2627    int i;
2628 
2629    consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
2630    consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
2631    assert(consdata1->sorted);
2632    assert(consdata2->sorted);
2633 #ifndef NDEBUG
2634    scip = (SCIP*)userptr;
2635    assert(scip != NULL);
2636 #endif
2637 
2638    /* checks trivial case */
2639    if( consdata1->nvars != consdata2->nvars )
2640       return FALSE;
2641 
2642    coefsequal = TRUE;
2643 
2644    for( i = 0; i < consdata1->nvars; ++i )
2645    {
2646       /* tests if variables are equal */
2647       if( consdata1->vars[i] != consdata2->vars[i] )
2648       {
2649          assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
2650             SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
2651          coefsequal = FALSE;
2652          break;
2653       }
2654       assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
2655    }
2656 
2657    return coefsequal;
2658 }
2659 
2660 /** returns the hash value of the key */
2661 static
SCIP_DECL_HASHKEYVAL(hashKeyValSetppccons)2662 SCIP_DECL_HASHKEYVAL(hashKeyValSetppccons)
2663 {
2664    SCIP_CONSDATA* consdata;
2665    int minidx;
2666    int mididx;
2667    int maxidx;
2668 #ifndef NDEBUG
2669    SCIP* scip;
2670 
2671    scip = (SCIP*)userptr;
2672    assert(scip != NULL);
2673 #endif
2674 
2675    consdata = SCIPconsGetData((SCIP_CONS*)key);
2676    assert(consdata != NULL);
2677    assert(consdata->nvars > 0);
2678 
2679    /* sorts the constraints */
2680    consdataSort(consdata);
2681 
2682    minidx = SCIPvarGetIndex(consdata->vars[0]);
2683    mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
2684    maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
2685    assert(minidx >= 0 && minidx <= maxidx);
2686 
2687    return SCIPhashFour(consdata->nvars, minidx, mididx, maxidx);
2688 }
2689 
2690 /** add extra clique-constraints resulting from a given cliquepartition to SCIP */
2691 static
addExtraCliques(SCIP * const scip,SCIP_VAR ** const binvars,int const nbinvars,int * const cliquepartition,int const ncliques,SCIP_CONS ** const usefulconss,int * const nusefulconss,int const nrounds,int * const nfixedvars,int * const naddconss,int * const ndelconss,int * const nchgcoefs,SCIP_Bool * const cutoff)2692 SCIP_RETCODE addExtraCliques(
2693    SCIP*const            scip,               /**< SCIP data structure */
2694    SCIP_VAR**const       binvars,            /**< binary variables to create clique constraints */
2695    int const             nbinvars,           /**< number of binary variables to create clique constraints */
2696    int*const             cliquepartition,    /**< clique partition of binary variables */
2697    int const             ncliques,           /**< number of cliques in cliquepartition */
2698    SCIP_CONS**const      usefulconss,        /**< storage for created constraints */
2699    int*const             nusefulconss,       /**< pointer to store number of useful created constraints */
2700    int const             nrounds,            /**< actual presolving round */
2701    int*const             nfixedvars,         /**< pointer to count number of deleted variables */
2702    int*const             naddconss,          /**< pointer to count number of added constraints */
2703    int*const             ndelconss,          /**< pointer to count number of deleted constraints */
2704    int*const             nchgcoefs,          /**< pointer to count number of deleted coefficients */
2705    SCIP_Bool*const       cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
2706    )
2707 {
2708    SCIP_CONS* cliquecons;
2709    char name[SCIP_MAXSTRLEN];
2710    int lastclqidx;
2711    int nadded;
2712    int c;
2713    int v;
2714 
2715    assert(scip != NULL);
2716    assert(binvars != NULL || nbinvars == 0);
2717    assert(cliquepartition != NULL || nbinvars == 0);
2718    assert(ncliques >= 0 && ncliques <= nbinvars);
2719    assert(usefulconss != NULL);
2720    assert(nusefulconss != NULL);
2721    assert(nfixedvars != NULL);
2722    assert(naddconss != NULL);
2723    assert(ndelconss != NULL);
2724    assert(nchgcoefs != NULL);
2725    assert(cutoff != NULL);
2726 
2727    /* no given binary variables */
2728    if( nbinvars == 0 || ncliques == 0 )
2729       return SCIP_OKAY;
2730 
2731    assert(binvars != NULL);
2732    assert(cliquepartition != NULL);
2733 
2734    /* no useful clique information */
2735    if( ncliques == nbinvars )
2736       return SCIP_OKAY;
2737 
2738    lastclqidx = 0;
2739 
2740    /* @todo: maybe sort cliques and accordingly the variables so it will be faster to add the constraints */
2741    for( c = 0; c < ncliques - 1; ++c )
2742    {
2743       if( lastclqidx >= cliquepartition[c] )
2744 	 continue;
2745 
2746       nadded = 0;
2747 
2748       /* name the clique constraint */
2749       (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "extra_clq_%d_round_%d", cliquepartition[c], nrounds);
2750       SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, 0, NULL,
2751 	    TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2752 
2753       /* add variables to clique constraint */
2754       for( v = c; v < nbinvars - 1; ++v )
2755       {
2756 	 if( cliquepartition[c] == cliquepartition[v] )
2757 	 {
2758 	    SCIP_CALL( addCoef(scip, cliquecons, binvars[v]) );
2759 	    ++nadded;
2760 	 }
2761       }
2762 
2763       /* @todo: try to find a good value for what are enough variables to create this constraint, maybe at least
2764        *        (nmaxvars(over all conss)-nminvars(over all conss))/2 */
2765       if( nadded >= 2 )
2766       {
2767 	 SCIP_CONSDATA* cliqueconsdata;
2768 
2769 	 SCIPdebugMsg(scip, " -> adding clique constraint: ");
2770 	 SCIPdebugPrintCons(scip, cliquecons, NULL);
2771 	 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
2772 	 ++(*naddconss);
2773 
2774 	 /* we only want to consider merged constraints */
2775 	 SCIP_CALL( mergeMultiples(scip, cliquecons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
2776 	 if( *cutoff )
2777 	 {
2778 	    SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2779 
2780 	    return SCIP_OKAY;
2781 	 }
2782 
2783 	 cliqueconsdata = SCIPconsGetData(cliquecons);
2784 	 assert(cliqueconsdata != NULL);
2785 
2786 	 /* the artificial constraints could be deleted while merging */
2787 	 if( !SCIPconsIsDeleted(cliquecons) && nadded - cliqueconsdata->nfixedzeros >= 2 )
2788 	 {
2789 	    assert(cliqueconsdata->nfixedones == 0);
2790 
2791 	    /* save the type and constraint */
2792 	    usefulconss[*nusefulconss] = cliquecons;
2793 	    ++(*nusefulconss);
2794 	 }
2795 	 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2796       }
2797       else
2798       {
2799 	 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2800       }
2801       lastclqidx = cliquepartition[c];
2802    }
2803 
2804    return SCIP_OKAY;
2805 }
2806 
2807 
2808 /** start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these
2809  *  constraints
2810  */
2811 static
collectCliqueConss(SCIP * const scip,SCIP_CONS ** const conss,int const nconss,SCIP_CONS ** const usefulconss,int * const nusefulconss,int * const nfixedvars,int * const ndelconss,int * const nchgcoefs,SCIP_Bool * const cutoff)2812 SCIP_RETCODE collectCliqueConss(
2813    SCIP*const            scip,               /**< SCIP data structure */
2814    SCIP_CONS**const      conss,              /**< constraint set */
2815    int const             nconss,             /**< number of constraints in constraint set */
2816    SCIP_CONS**const      usefulconss,        /**< storage for created constraints */
2817    int*const             nusefulconss,       /**< pointer to store number of useful created constraints */
2818    int*const             nfixedvars,         /**< pointer to count number of deleted variables */
2819    int*const             ndelconss,          /**< pointer to count number of deleted constraints */
2820    int*const             nchgcoefs,          /**< pointer to count number of deleted coefficients */
2821    SCIP_Bool*const       cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
2822    )
2823 {
2824    SCIP_CONS* cons;
2825    SCIP_CONSDATA* consdata;
2826    SCIP_Bool addcut;
2827    SCIP_Bool mustcheck;
2828    int nlocaladdconss = 0;
2829    int c;
2830 
2831    assert(scip != NULL);
2832    assert(conss != NULL || nconss == 0);
2833    assert(usefulconss != NULL);
2834    assert(nusefulconss != NULL);
2835    assert(nfixedvars != NULL);
2836    assert(ndelconss != NULL);
2837    assert(nchgcoefs != NULL);
2838    assert(cutoff != NULL);
2839 
2840    if( nconss == 0 )
2841       return SCIP_OKAY;
2842 
2843    assert(conss != NULL);
2844 
2845    for( c = nconss - 1; c >= 0; --c )
2846    {
2847       cons = conss[c];
2848 
2849       /* we only want to consider constraints with either active or negated of active variables, applyfixings removes
2850        * aggregated and fixed variables to zero, processFixings removes fixings to one but no aggregation
2851        *
2852        * @todo: maybe write a new method for deleting aggregations and all fixings
2853        */
2854       SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
2855       if( *cutoff )
2856          return SCIP_OKAY;
2857 
2858       if( SCIPconsIsDeleted(cons) )
2859       {
2860          /* reset nlocaladdconss and continue */
2861          nlocaladdconss = 0;
2862          continue;
2863       }
2864       assert(nlocaladdconss == 0);
2865 
2866       SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) );
2867       if( *cutoff )
2868          return SCIP_OKAY;
2869 
2870       consdata = SCIPconsGetData(cons);
2871       assert(consdata != NULL);
2872 
2873       /* we only want to consider merged constraints */
2874       SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
2875       if( *cutoff )
2876          return SCIP_OKAY;
2877 
2878       if( SCIPconsIsModifiable(cons) || !SCIPconsIsActive(cons) )
2879          continue;
2880 
2881       assert(consdata->nfixedones == 0);
2882 
2883       if( consdata->nvars == 0 )
2884          continue;
2885 
2886       /* @todo: check for covering constraints with only two variables which are equal to a packing constraint with
2887        * negated variables */
2888       if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2889       {
2890          assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2891 
2892          usefulconss[*nusefulconss] = cons;
2893          ++(*nusefulconss);
2894       }
2895    }
2896 
2897    return SCIP_OKAY;  /*lint !e438*/
2898 }
2899 
2900 /** creating all necessary data in array structure, collect all clique constraint variables and occurrences,
2901  *  @note works only with merged and active not set-covering constraints
2902  */
2903 static
collectCliqueData(SCIP * const scip,SCIP_CONS ** const usefulconss,int const nusefulconss,SCIP_VAR ** const usefulvars,int * const nusefulvars,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs,int * const maxnvars)2904 SCIP_RETCODE collectCliqueData(
2905    SCIP*const            scip,               /**< SCIP data structure */
2906    SCIP_CONS**const      usefulconss,        /**< clique constraints */
2907    int const             nusefulconss,       /**< number of clique constraints */
2908    SCIP_VAR**const       usefulvars,         /**< storage for all found variables */
2909    int*const             nusefulvars,        /**< pointer to store number of added variables */
2910    SCIP_HASHMAP*const    vartoindex,         /**< hashmap mapping variables to indices */
2911    int*const             varnconss,          /**< storage for remembering the number of constraints a variable occurs */
2912    int*const             maxnvarconsidx,     /**< storage for the maximal number of occurrences of a variable */
2913    int**const            varconsidxs,        /**< storage for constraint indices in which the corresponding variable exists */
2914    int*const             maxnvars            /**< pointer to store maximal number of variables of a constraint */
2915    )
2916 {
2917    SCIP_CONS* cons;
2918    SCIP_CONSDATA* consdata;
2919    int varindex;
2920    int c;
2921    int v;
2922 
2923    assert(scip != NULL);
2924    assert(usefulconss != NULL || nusefulconss == 0);
2925    assert(usefulvars != NULL);
2926    assert(nusefulvars != NULL);
2927    assert(vartoindex != NULL);
2928    assert(varnconss != NULL);
2929    assert(maxnvarconsidx != NULL);
2930    assert(varconsidxs != NULL);
2931    assert(maxnvars != NULL);
2932 
2933    if( nusefulconss == 0 )
2934       return SCIP_OKAY;
2935 
2936    assert(usefulconss != NULL);
2937 
2938    for( c = nusefulconss - 1; c >= 0; --c )
2939    {
2940       cons = usefulconss[c];
2941 
2942       assert(SCIPconsIsActive(cons));
2943 
2944       consdata = SCIPconsGetData(cons);
2945       assert(consdata != NULL);
2946 
2947       /* here we should have no covering constraints anymore and the constraint data should be merged */
2948       assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2949       assert(consdata->merged);
2950 
2951       /* save maximal number of vars */
2952       if( consdata->nvars > *maxnvars )
2953          *maxnvars = consdata->nvars;
2954 
2955       /* adding variables and information about occurrences to local data structure */
2956       for( v = consdata->nvars - 1; v >= 0; --v )
2957       {
2958          SCIP_VAR* var;
2959 
2960          var = consdata->vars[v];
2961          assert(var != NULL);
2962 
2963          /* don't remember fixed vars */
2964          if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
2965             continue;
2966 
2967 	 /* only collect active or negated active variables */
2968 	 assert(SCIPvarIsActive(var) || (SCIPvarIsNegated(var) && SCIPvarIsActive(SCIPvarGetNegationVar(var))));
2969 
2970          if( !SCIPhashmapExists(vartoindex, (void*) var) )
2971          {
2972             SCIP_VAR* tmpvar;
2973 
2974             usefulvars[*nusefulvars] = var;
2975             ++(*nusefulvars);
2976             varindex = *nusefulvars;
2977             SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, varindex) );
2978 
2979             /* get the maximal number of occurrences of this variable, if this variables  */
2980             tmpvar = SCIPvarIsNegated(var) ? SCIPvarGetNegatedVar(var) : var;
2981             maxnvarconsidx[varindex] = SCIPvarGetNLocksDownType(tmpvar, SCIP_LOCKTYPE_MODEL)
2982                + SCIPvarGetNLocksUpType(tmpvar, SCIP_LOCKTYPE_MODEL);
2983             SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) );  /*lint !e866*/
2984          }
2985          else
2986          {
2987             assert(SCIPhashmapExists(vartoindex, (void*) var));
2988             varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var);
2989          }
2990 
2991          /* the number of occurrences of a variable is not limited by the locks (so maybe we have to increase memory),
2992           * because for examples converted cuts are not check and therefore they have no locks on their variables */
2993          if( varnconss[varindex] == maxnvarconsidx[varindex] )
2994          {
2995             maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1);
2996             SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
2997          }
2998 
2999          assert(varnconss[varindex] < maxnvarconsidx[varindex]);
3000          /* add the constraint number to the variable list */
3001          varconsidxs[varindex][varnconss[varindex]] = c;
3002          /* increase number of occurrences for variables */
3003          ++(varnconss[varindex]);
3004       }
3005    } /* data structure created */
3006 
3007    return SCIP_OKAY;
3008 }
3009 
3010 /** correct clique data due to an aggregation */
3011 static
deleteCliqueDataEntry(SCIP_VAR * const var,int const considx,SCIP_HASHMAP * const vartoindex,int * const varnconss,int ** const varconsidxs)3012 void deleteCliqueDataEntry(
3013    SCIP_VAR*const        var,                /**< variable which appears less */
3014    int const             considx,            /**< constraint index which to remove */
3015    SCIP_HASHMAP*const    vartoindex,         /**< hashmap mapping variables to indices */
3016    int*const             varnconss,          /**< storage for remembering the number of constraints a variable occurs */
3017    int**const            varconsidxs         /**< storage for constraint indices in which the corresponding variable exists */
3018    )
3019 {
3020    int varindex;
3021    int i;
3022 #ifndef NDEBUG
3023    SCIP_Bool found = FALSE;
3024 #endif
3025 
3026    assert(var != NULL);
3027    assert(SCIPvarGetLbLocal(var) < 0.5 && SCIPvarGetUbLocal(var) > 0.5);
3028    assert(considx >= 0);
3029    assert(vartoindex != NULL);
3030    assert(varnconss != NULL);
3031    assert(varconsidxs != NULL);
3032 
3033    assert(SCIPhashmapExists(vartoindex, (void*) var));
3034    varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var);
3035 
3036    /* remove entry of variable at the given position */
3037    for( i = 0; i < varnconss[varindex]; ++i )
3038    {
3039       if( varconsidxs[varindex][i] == considx )
3040       {
3041 	 varconsidxs[varindex][i] = varconsidxs[varindex][varnconss[varindex] - 1];
3042 #ifndef NDEBUG
3043 	 found = TRUE;
3044 #endif
3045 	 --(varnconss[varindex]);
3046 	 break;
3047       }
3048    }
3049    assert(found);
3050 }
3051 
3052 /* correct local data structure, add constraint entry to variable data  */
3053 static
addCliqueDataEntry(SCIP * const scip,SCIP_VAR * const addvar,int const considx,SCIP_Bool const maybenew,SCIP_VAR ** const usefulvars,int * const nusefulvars,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs)3054 SCIP_RETCODE addCliqueDataEntry(
3055    SCIP*const            scip,               /**< SCIP data structure */
3056    SCIP_VAR*const        addvar,             /**< variable which was added */
3057    int const             considx,            /**< constraint index which to add */
3058    SCIP_Bool const       maybenew,           /**< could be a new variables, a negated of an already existing */
3059    SCIP_VAR**const       usefulvars,         /**< storage for all found variables */
3060    int*const             nusefulvars,        /**< pointer to store number of added variables */
3061    SCIP_HASHMAP*const    vartoindex,         /**< hashmap mapping variables to indices */
3062    int*const             varnconss,          /**< storage for remembering the number of constraints a variable occurs */
3063    int*const             maxnvarconsidx,     /**< storage for the maximal number of occurrences of a variable */
3064    int**const            varconsidxs         /**< storage for constraint indices in which the corresponding variable exists */
3065    )
3066 {
3067    int varindex;
3068 
3069    assert(scip != NULL);
3070    assert(addvar != NULL);
3071    assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
3072    assert(usefulvars != NULL);
3073    assert(nusefulvars != NULL);
3074    assert(vartoindex != NULL);
3075    assert(varnconss != NULL);
3076    assert(maxnvarconsidx != NULL);
3077    assert(varconsidxs != NULL);
3078 
3079    /* we add the variable to the hashmap if its new */
3080    if( maybenew && !SCIPhashmapExists(vartoindex, (void*) addvar) )
3081    {
3082       assert(SCIPvarIsActive(addvar) || SCIPvarIsNegated(addvar));
3083       assert(SCIPvarGetNegatedVar(addvar) != NULL && SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(addvar)));
3084 
3085       /* @note because we can only have created a negated variable, and we already allocated enough memory for
3086        * all (even not existing) negated variables the usefulvars array should be big enough
3087        */
3088       SCIPsortedvecInsertDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, addvar, nusefulvars, NULL);
3089       varindex = *nusefulvars;
3090       SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) addvar, varindex) );
3091 
3092       assert(varconsidxs[varindex] == NULL);
3093 
3094       maxnvarconsidx[varindex] = 1;
3095       SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3096       varnconss[varindex] = 0;
3097    }
3098    else
3099    {
3100       varindex = SCIPhashmapGetImageInt(vartoindex, (void*) addvar);
3101 
3102       /* grow the needed memory if we added a variable */
3103       if( varnconss[varindex] == maxnvarconsidx[varindex] )
3104       {
3105 	 maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1);
3106 	 SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3107       }
3108    }
3109    assert(varnconss[varindex] < maxnvarconsidx[varindex]);
3110    varconsidxs[varindex][varnconss[varindex]] = considx;
3111 
3112    /* increase number of occurrences for variables */
3113    ++(varnconss[varindex]);
3114 
3115    return SCIP_OKAY;
3116 }
3117 
3118 
3119 /** check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
3120  *  possible
3121  */
3122 static
presolvePropagateCons(SCIP * const scip,SCIP_CONS * const cons,SCIP_Bool const aggregate,SCIP_VAR ** undoneaggrvars,SCIP_Bool * undoneaggrtypes,int * const naggregations,int * const saggregations,int * const nfixedvars,int * const naggrvars,int * const ndelconss,SCIP_Bool * const cutoff)3123 SCIP_RETCODE presolvePropagateCons(
3124    SCIP*const            scip,               /**< SCIP data structure */
3125    SCIP_CONS*const       cons,               /**< constraint */
3126    SCIP_Bool const       aggregate,          /**< try to aggregate if possible */
3127    SCIP_VAR**            undoneaggrvars,     /**< array to store aggregation variables, if aggregation is not performed
3128 					      *   yet; both variables are standing next to each other; or NULL if
3129 					      *   aggregate == TRUE
3130 					      */
3131    SCIP_Bool*            undoneaggrtypes,    /**< array to store aggregation type, if aggregation is not performed yet;
3132 					      *   type FALSE means the aggregation is of the form x + y = 1; type TRUE means
3133 					      *   the aggregation is of the form x = y; or NULL if aggregate == TRUE
3134 					      */
3135    int*const             naggregations,      /**< pointer to store number of aggregations which are not yet performed;
3136 					      *   or NULL if aggregate == TRUE
3137 					      */
3138    int*const             saggregations,      /**< pointer to store size of the array for aggregation type and two times
3139 					      *   the value is the size of the array for the aggregation variables which
3140 					      *   are not yet performed; or NULL if aggregate == TRUE
3141 					      */
3142    int*const             nfixedvars,         /**< pointer to count number of deleted variables */
3143    int*const             naggrvars,          /**< pointer to count number of aggregated variables */
3144    int*const             ndelconss,          /**< pointer to count number of deleted constraints */
3145    SCIP_Bool*const       cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
3146    )
3147 {
3148    SCIP_CONSDATA* consdata;
3149    SCIP_VAR** vars;
3150    int nvars;
3151    int v;
3152    SCIP_Bool fixed;
3153 
3154    assert(scip != NULL);
3155    assert(cons != NULL);
3156    assert(nfixedvars != NULL);
3157    assert(naggrvars != NULL);
3158    assert(ndelconss != NULL);
3159    assert(cutoff != NULL);
3160 
3161    if( !SCIPconsIsActive(cons) )
3162       return SCIP_OKAY;
3163 
3164    consdata = SCIPconsGetData(cons);
3165    assert(consdata != NULL);
3166 
3167    if( consdata->presolpropagated )
3168       return SCIP_OKAY;
3169 
3170    consdata->presolpropagated = TRUE;
3171 
3172    vars = consdata->vars;
3173    nvars = consdata->nvars;
3174 
3175    /* no variables left */
3176    if( nvars == 0 && !SCIPconsIsModifiable(cons) )
3177    {
3178       if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3179       {
3180 	 SCIPdebugMsg(scip, "empty set-partition/-covering constraint <%s> found -> cutoff\n", SCIPconsGetName(cons));
3181 	 *cutoff = TRUE;
3182 
3183 	 return SCIP_OKAY;
3184       }
3185       else
3186       {
3187 	 assert(consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
3188 
3189 	 /* delete constraint */
3190 	 SCIPdebugMsg(scip, " -> deleting constraint <%s>, no variables left\n", SCIPconsGetName(cons));
3191 	 SCIP_CALL( SCIPdelCons(scip, cons) );
3192 	 ++(*ndelconss);
3193 
3194 	 return SCIP_OKAY;
3195       }
3196    }
3197 
3198    /* more then two variables are fixed */
3199    if( consdata->nfixedones > 1 )
3200    {
3201       /* at least two variables are fixed to 1:
3202        * - a set covering constraint is feasible anyway and can be deleted
3203        * - a set partitioning or packing constraint is infeasible
3204        */
3205       if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3206       {
3207 	 /* delete constraint */
3208 	 SCIPdebugMsg(scip, " -> deleting set-covering constraint <%s>, at least two variables are fixed to 1\n", SCIPconsGetName(cons));
3209 	 SCIP_CALL( SCIPdelCons(scip, cons) );
3210 	 ++(*ndelconss);
3211 
3212 	 return SCIP_OKAY;
3213       }
3214 
3215       SCIPdebugMsg(scip, "set partitioning / packing constraint <%s> is infeasible, %d variables fixed to one\n", SCIPconsGetName(cons), consdata->nfixedones);
3216       *cutoff = TRUE;
3217 
3218       return SCIP_OKAY;
3219    }
3220 
3221    if( consdata->nfixedones == 1 )
3222    {
3223       /* exactly one variable is fixed to 1:
3224        * - a set covering constraint is feasible anyway and can be disabled
3225        * - all other variables in a set partitioning or packing constraint must be zero
3226        */
3227       if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING && consdata->nfixedzeros < nvars - 1 ) /*lint !e641*/
3228       {
3229          assert(vars != NULL);
3230 
3231 	 for( v = nvars - 1; v >= 0; --v )
3232 	 {
3233 	    if( SCIPvarGetLbLocal(vars[v]) + 0.5 < SCIPvarGetUbLocal(vars[v]) )
3234 	    {
3235 	       SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(vars[v]));
3236 
3237 	       /* fix all remaining variables to zero, constraint is already feasible or infeasible */
3238 	       SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3239 	       if( *cutoff )
3240 	       {
3241 		  SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
3242 		     SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
3243 
3244 		  return SCIP_OKAY;
3245 	       }
3246 
3247 	       assert(fixed);
3248 	       ++(*nfixedvars);
3249 	    }
3250 	 }
3251       }
3252 
3253       if( !SCIPconsIsModifiable(cons) || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3254       {
3255 	 /* delete constraint */
3256 	 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3257 	 assert(SCIPconsIsActive(cons));
3258 	 SCIP_CALL( SCIPdelCons(scip, cons) );
3259 	 ++(*ndelconss);
3260       }
3261 
3262       return SCIP_OKAY;
3263    }
3264 
3265    /* other propagations can only be done on not modifiable constraints */
3266    if( SCIPconsIsModifiable(cons) )
3267       return SCIP_OKAY;
3268 
3269    assert(vars != NULL);
3270 
3271    /* all variables were fixed to zero then either delete the constraint or stop with infeasibility */
3272    if( consdata->nfixedzeros == nvars )
3273    {
3274       assert(consdata->nfixedones == 0);
3275 
3276       /* all variables are fixed to zero:
3277        * - a set packing constraint is feasible anyway and can be deleted
3278        * - a set partitioning or covering constraint is infeasible, and so is the whole problem
3279        */
3280       if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3281       {
3282 	 SCIPdebugMsg(scip, "set partitioning / covering constraint <%s> is infeasible\n", SCIPconsGetName(cons));
3283 	 *cutoff = TRUE;
3284 
3285 	 return SCIP_OKAY;
3286       }
3287 
3288       /* delete constraint */
3289       SCIPdebugMsg(scip, " -> deleting set-packing constraint <%s>, all variables are fixed to zero\n", SCIPconsGetName(cons));
3290       assert(SCIPconsIsActive(cons));
3291       SCIP_CALL( SCIPdelCons(scip, cons) );
3292       ++(*ndelconss);
3293 
3294       return SCIP_OKAY;
3295    }
3296 
3297    /* all but one variable were fixed to zero then delete the constraint and for setpartition fix the remaining variable to 1 */
3298    if( consdata->nfixedzeros + 1 == nvars )
3299    {
3300       assert(consdata->nfixedones == 0);
3301 
3302       /* all variables except one are fixed to zero:
3303        * - a set packing constraint is feasible anyway, and can be deleted
3304        * - a set partitioning or covering constraint is feasible and can be deleted after the
3305        *   remaining variable is fixed to one
3306        */
3307       if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3308       {
3309 	 fixed = FALSE;
3310 	 for( v = nvars - 1; v >= 0; --v )
3311 	 {
3312 	    assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
3313 	    if( SCIPvarGetUbLocal(vars[v]) > 0.5 )
3314 	    {
3315 	       SCIPdebugMsg(scip, "trying to fix <%s> to 1 due to it's the last unfixed variable is the set-partitioning/covering constraint\n", SCIPvarGetName(vars[v]));
3316 
3317 	       /* fix the remaining set partition variable */
3318 	       SCIP_CALL( SCIPfixVar(scip, vars[v], 1.0, cutoff, &fixed) );
3319 	       if( *cutoff )
3320 	       {
3321                   SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 1\n",
3322                      SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
3323 
3324 		  return SCIP_OKAY;
3325 	       }
3326 
3327 	       assert(fixed);
3328 	       ++(*nfixedvars);
3329 	       break;
3330 	    }
3331 	 }
3332 	 assert(fixed);
3333       }
3334 
3335       /* delete constraint */
3336       SCIPdebugMsg(scip, " -> deleting constraint <%s>, all %svariables are fixed\n", SCIPconsGetName(cons), consdata->setppctype == (int) SCIP_SETPPCTYPE_PACKING ? "but one " : "");
3337       assert(SCIPconsIsActive(cons));
3338       SCIP_CALL( SCIPdelCons(scip, cons) );
3339       ++(*ndelconss);
3340 
3341       return SCIP_OKAY;
3342    }
3343 
3344    /* all but two variable were fixed to zero in a setpartitioning constraint then delete the constraint and
3345     * aggregate the remaining two variables
3346     */
3347    if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros + 2 == nvars ) /*lint !e641*/
3348    {
3349       SCIP_VAR* var;
3350 
3351       var = NULL;
3352       for( v = nvars - 1; v >= 0; --v )
3353       {
3354 	 assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
3355 
3356 	 if( SCIPvarGetUbLocal(vars[v]) > 0.5 )
3357 	 {
3358 	    if( var == NULL )
3359 	       var = vars[v];
3360 	    else
3361 	    {
3362 	       SCIP_Bool redundant;
3363 	       SCIP_Bool aggregated;
3364 #ifdef VARUSES
3365 	       SCIP_CONSHDLR* conshdlr;
3366 	       SCIP_CONSHDLRDATA* conshdlrdata;
3367 
3368 	       /* get event handler and event handler data */
3369 	       conshdlr = SCIPconsGetHdlr(cons);
3370 	       assert(conshdlr != NULL);
3371 	       conshdlrdata = SCIPconshdlrGetData(conshdlr);
3372 	       assert(conshdlrdata != NULL);
3373 #endif
3374 	       if( aggregate )
3375 	       {
3376 		  SCIPdebugMsg(scip, "trying to aggregate <%s> and <%s> due to they are the last two unfixed variables in the set partitionning constraint <%s>\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]), SCIPconsGetName(cons));
3377 
3378 #ifdef VARUSES
3379 		  /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate,
3380 		   * and increase usage counting again
3381 		   */
3382 		  SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var) );
3383 		  SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, vars[v]) );
3384 #endif
3385 
3386 		  /* aggregate last remaining variables in the set partitioning constraint */
3387 		  SCIP_CALL( SCIPaggregateVars(scip, var, vars[v], 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) );
3388 		  if( *cutoff )
3389 		  {
3390 		     SCIPdebugMsg(scip, "set partitioning constraint <%s>: aggregate <%s> + <%s> == 1\n",
3391 			SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetName(vars[v]));
3392 
3393 		     return SCIP_OKAY;
3394 		  }
3395 
3396 #ifdef VARUSES
3397 		  /* increase variable usage counting again */
3398 		  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) );
3399 		  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, vars[v]) );
3400 #endif
3401 
3402 		  if( aggregated )
3403 		     ++(*naggrvars);
3404 
3405 		  if( redundant )
3406 		  {
3407 		     /* delete constraint */
3408 		     SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3409 		     assert(SCIPconsIsActive(cons));
3410 		     SCIP_CALL( SCIPdelCons(scip, cons) );
3411 		     ++(*ndelconss);
3412 		  }
3413 	       }
3414 	       else
3415 	       {
3416 		  assert(undoneaggrvars != NULL);
3417 		  assert(undoneaggrtypes != NULL);
3418 		  assert(naggregations != NULL);
3419 		  assert(saggregations != NULL);
3420 
3421 		  SCIPdebugMsg(scip, "memorize the aggregation of <%s> + <%s> = 1, because they are the last two unfixed variable in the set partitioning constraints <%s>\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]), SCIPconsGetName(cons));
3422 
3423 		  /* resize the aggregation arrays if necessary */
3424 		  if( *saggregations == *naggregations )
3425 		  {
3426 		     *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1);
3427 		     assert(*saggregations > *naggregations);
3428 		     SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) );
3429 		     SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) );
3430 
3431 		     /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */
3432 		     BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/
3433 		  }
3434 
3435 		  /* memorize aggregation variables*/
3436 		  assert(undoneaggrtypes[*naggregations] == FALSE);
3437 		  undoneaggrvars[2 * (*naggregations)] = var;
3438 		  undoneaggrvars[2 * (*naggregations) + 1] = vars[v];
3439 		  ++(*naggregations);
3440 
3441 		  if( !SCIPdoNotAggr(scip) )
3442 		  {
3443 		     /* delete constraint */
3444 		     SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3445 		     assert(SCIPconsIsActive(cons));
3446 		     SCIP_CALL( SCIPdelCons(scip, cons) );
3447 		     ++(*ndelconss);
3448 		  }
3449 	       }
3450 
3451 	       return SCIP_OKAY;
3452 	    }
3453 	 }
3454       }
3455       /* we should never be here, because the last to unfixed variables should have been either aggregated or a cutoff
3456        * should be applied
3457        */
3458       assert(FALSE); /*lint !e506*/
3459    }
3460 
3461    return SCIP_OKAY;
3462 }
3463 
3464 /** check for overlapping constraint */
3465 static
checkForOverlapping(SCIP * const scip,SCIP_CONS * const cons,int const considx,int const endidx,SCIP_CONS ** const usefulconss,int const nusefulconss,SCIP_VAR ** const usefulvars,int * const nusefulvars,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs,int * const countofoverlapping,SCIP_Bool const shrinking,SCIP_Bool * const chgcons,SCIP_VAR ** undoneaggrvars,SCIP_Bool * undoneaggrtypes,int * const naggregations,int * const saggregations,int * const nfixedvars,int * const naggrvars,int * const nchgcoefs,int * const ndelconss,SCIP_Bool * const cutoff)3466 SCIP_RETCODE checkForOverlapping(
3467    SCIP*const            scip,               /**< SCIP data structure */
3468    SCIP_CONS*const       cons,               /**< constraint which may overlap */
3469    int const             considx,            /**< constraint index to avoid checking against itself */
3470    int const             endidx,             /**< end index to check against given constraint */
3471    SCIP_CONS**const      usefulconss,        /**< clique constraints */
3472    int const             nusefulconss,       /**< number of clique constraints */
3473    SCIP_VAR**const       usefulvars,         /**< storage for all found variables */
3474    int*const             nusefulvars,        /**< pointer to store number of added variables */
3475    SCIP_HASHMAP*const    vartoindex,         /**< hashmap mapping variables to indices */
3476    int*const             varnconss,          /**< storage for remembering the number of constraints a variable occurs */
3477    int*const             maxnvarconsidx,     /**< storage for the maximal number of occurrences of a variable */
3478    int**const            varconsidxs,        /**< storage for constraint indices in which the corresponding variable exists */
3479    int*const             countofoverlapping, /**< the amount of variables of cons which overlap in all other constraint */
3480    SCIP_Bool const       shrinking,          /**< try to replace some variables with one variable */
3481    SCIP_Bool*const       chgcons,            /**< pointer to store if the given constraint was changed, due to
3482 					      *   added/deleted variables
3483 					      */
3484    SCIP_VAR**            undoneaggrvars,     /**< array to store aggregation variables, if aggregation is not performed
3485 					      *   yet; both variables are standing next to each other;
3486 					      */
3487    SCIP_Bool*            undoneaggrtypes,    /**< array to store aggregation type, if aggregation is not performed yet;
3488 					      *   type FALSE means the aggregation is of the form x + y = 1; type TRUE means
3489 					      *   the aggregation is of the form x = y;
3490 					      */
3491    int*const             naggregations,      /**< pointer to store number of aggregations which are not yet performed; */
3492    int*const             saggregations,      /**< pointer to store size of the array for aggregation type and two times
3493 					      *   the value is the size of the array for the aggregation variables which
3494 					      *   are not yet performed;
3495 					      */
3496    int*const             nfixedvars,         /**< pointer to count number of deleted variables */
3497    int*const             naggrvars,          /**< pointer to count number of aggregated variables */
3498    int*const             nchgcoefs,          /**< pointer to count number of changed coefficients */
3499    int*const             ndelconss,          /**< pointer to count number of deleted constraints */
3500    SCIP_Bool*const       cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
3501    )
3502 {
3503    SCIP_CONS* cons1;
3504    SCIP_CONSDATA* consdata1;
3505    SCIP_CONSDATA* consdata;
3506    SCIP_VAR** vars;
3507    SCIP_VAR** vars1;
3508    SCIP_VAR* var;
3509    SCIP_VAR* var1;
3510    SCIP_Bool fixed;
3511    SCIP_Bool overlapdestroyed;
3512    int nvars;
3513    int nvars1;
3514    int oldnfixedzeros;
3515    int c;
3516    int v;
3517    int v1;
3518 #ifndef NDEBUG
3519    int oldnaggrvars;
3520 #endif
3521 
3522    assert(scip != NULL);
3523    assert(cons != NULL);
3524    assert(usefulconss != NULL && nusefulconss > 0);
3525    assert(0 <= considx && considx < nusefulconss);
3526    assert(usefulconss[considx] == cons);
3527    assert(0 <= endidx && endidx <= nusefulconss);
3528    assert(countofoverlapping != NULL);
3529    assert(chgcons != NULL);
3530    assert(undoneaggrvars != NULL);
3531    assert(undoneaggrtypes != NULL);
3532    assert(naggregations != NULL);
3533    assert(saggregations != NULL);
3534    assert(nfixedvars != NULL);
3535    assert(naggrvars != NULL);
3536    assert(nchgcoefs != NULL);
3537    assert(ndelconss != NULL);
3538    assert(cutoff != NULL);
3539 
3540    if( !SCIPconsIsActive(cons) )
3541       return SCIP_OKAY;
3542 
3543    consdata = SCIPconsGetData(cons);
3544    assert(consdata != NULL);
3545 
3546    nvars = consdata->nvars;
3547 
3548    if( nvars == 0 )
3549       return SCIP_OKAY;
3550 
3551    vars = consdata->vars;
3552    assert(vars != NULL);
3553 
3554    oldnfixedzeros = consdata->nfixedzeros;
3555    overlapdestroyed = FALSE;
3556 
3557    /* first check for redundancy for all unprocessed constraints with cons */
3558    for( c = endidx - 1; c >= 0; --c )
3559    {
3560       cons1 = usefulconss[c];
3561 
3562       if( !SCIPconsIsActive(cons1) )
3563 	 continue;
3564 
3565       /* avoid checking constraint against itself */
3566       if( considx == c )
3567 	 continue;
3568 
3569       assert(usefulconss[c] != cons);
3570 
3571 #ifndef NDEBUG
3572       oldnaggrvars = *naggrvars;
3573 #endif
3574 
3575       /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
3576        * possible
3577        */
3578       SCIP_CALL( presolvePropagateCons(scip, cons1, FALSE, undoneaggrvars, undoneaggrtypes, naggregations, saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
3579 
3580       if( *cutoff )
3581 	 return SCIP_OKAY;
3582 
3583       /* we can't handle aggregated variables later on so we should have saved them for later */
3584       assert(*naggrvars == oldnaggrvars);
3585 
3586       if( !SCIPconsIsActive(cons1) )
3587 	 continue;
3588 
3589       consdata1 = SCIPconsGetData(cons1);
3590       assert(consdata1 != NULL);
3591 
3592       nvars1 = consdata1->nvars;
3593 
3594       if( nvars1 == 0 )
3595 	 continue;
3596 
3597       /* no more variables from cons as nvars1 can overlap */
3598       assert(countofoverlapping[c] <= nvars1);
3599 
3600       /* constraint should not be redundant or infeasible */
3601       assert(consdata1->nfixedones == 0);
3602 
3603       SCIPdebugMsg(scip, "constraint <%s> overlaps with constraint <%s> by %d variables\n", SCIPconsGetName(cons), SCIPconsGetName(cons1), countofoverlapping[c]);
3604 
3605       /* cons1 includes cons */
3606       if( !overlapdestroyed && countofoverlapping[c] == nvars - consdata->nfixedzeros )
3607       {
3608 	 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
3609 	 {
3610 	    if( nvars - consdata->nfixedzeros < nvars1 )
3611 	    {
3612 #ifndef NDEBUG
3613 	       SCIP_Bool negated0;
3614 	       SCIP_Bool negated1;
3615 #endif
3616 
3617 	       /* both constraints should stay merged */
3618 	       assert(consdata->merged);
3619 	       assert(consdata1->merged);
3620 
3621 	       vars1 = consdata1->vars;
3622 	       assert(vars1 != NULL);
3623 
3624 	       /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3625 	       SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3626 	       /* standard setppc-sorting now lost */
3627 	       consdata1->sorted = FALSE;
3628 
3629 	       /* iterate over the both cliques variables the "same" time */
3630 	       for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3631 	       {
3632 		  if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3633 		  {
3634 		     --v1;
3635 		     continue;
3636 		  }
3637 		  if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3638 		  {
3639 		     --v;
3640 		     continue;
3641 		  }
3642 
3643 		  /* all variables inside the second clique constraint should be either active or negated of an active one */
3644 		  assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3645 
3646 		  /* get not negated variable and clique value in cons */
3647 		  if( SCIPvarGetStatus(vars[v]) != SCIP_VARSTATUS_NEGATED )
3648 		  {
3649 		     var = vars[v];
3650 #ifndef NDEBUG
3651 		     negated0 = FALSE;
3652 #endif
3653 		  }
3654 		  else
3655 		  {
3656 		     var = SCIPvarGetNegationVar(vars[v]);
3657 #ifndef NDEBUG
3658 		     negated0 = TRUE;
3659 #endif
3660 		  }
3661 
3662 		  /* get active variable and clique value of next variable */
3663 		  if( SCIPvarIsActive(vars1[v1]) )
3664 		  {
3665 		     var1 = vars1[v1];
3666 #ifndef NDEBUG
3667 		     negated1 = FALSE;
3668 #endif
3669 		  }
3670 		  else
3671 		  {
3672 		     assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])));
3673 		     var1 = SCIPvarGetNegationVar(vars1[v1]);
3674 #ifndef NDEBUG
3675 		     negated1 = TRUE;
3676 #endif
3677 		  }
3678 
3679 		  /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
3680 		  if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1)  )
3681 		     --v;
3682 		  /* variable index in the constraint is greater than the other one, so fix this variable */
3683 		  else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1)  )
3684 		  {
3685 		     SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars1[v1]));
3686 
3687 		     /* fix all variables except the one which has the negated var in the clique to zero */
3688 		     SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) );
3689 		     if( *cutoff )
3690 		     {
3691 			SCIPdebugMsg(scip, "fixing led to cutoff\n");
3692 
3693 			return SCIP_OKAY;
3694 		     }
3695 
3696 		     assert(fixed);
3697 		     ++(*nfixedvars);
3698 		     --v1;
3699 		  }
3700 		  else
3701 		  {
3702 		     /* because the constraint's are merged it is not possible that one constraint contains a negated
3703 		      * variable of another and because all variables in cons are in cons1 this should be really the
3704 		      * same variable here; so we can decrease v and v1
3705 		      */
3706 		     assert(negated0 == negated1);
3707 
3708 		     --v;
3709 		     --v1;
3710 		  }
3711 	       }
3712 	       /* maybe we ended because of cons(v reached -1) so try to add rest of cons1 to cons */
3713 	       for( ; v1 >= 0; --v1)
3714 	       {
3715 		  if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3716 		     continue;
3717 
3718 		  SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars1[v1]));
3719 
3720 		  /* fix all variables except the one which has the negated var in the clique to zero */
3721 		  SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) );
3722 		  if( *cutoff )
3723 		  {
3724 		     SCIPdebugMsg(scip, "fixing led to cutoff\n");
3725 
3726 		     return SCIP_OKAY;
3727 		  }
3728 
3729 		  assert(fixed);
3730 		  ++(*nfixedvars);
3731 	       }
3732 	    }
3733 
3734 	    /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was
3735 	     * fixed to one, it's infeasible */
3736 	    if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nfixedzeros == nvars1 && consdata1->nfixedones != 1 ) /*lint !e641*/
3737 	    {
3738 	       SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1));
3739 	       *cutoff = TRUE;
3740 
3741 	       return SCIP_OKAY;
3742 	    }
3743 
3744 	    assert(SCIPconsIsActive(cons1));
3745 	    /* delete second constraint */
3746 	    SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx);
3747 
3748             SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
3749 	    SCIP_CALL( SCIPdelCons(scip, cons1) );
3750 	    ++(*ndelconss);
3751 	 }
3752 	 /* could already be deleted because the constraint was included in another set partition constraint */
3753 	 else if( SCIPconsIsActive(cons) )
3754 	 {
3755 	    /* delete cons due to redundancy to cons1 */
3756 	    SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c);
3757 
3758             SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) );
3759 	    SCIP_CALL( SCIPdelCons(scip, cons) );
3760 	    ++(*ndelconss);
3761 	 }
3762       }
3763       /* cons includes cons1
3764        *
3765        * @note that zero fixations from above can only appear through a set-partitioning constraint, this means if
3766        *       cons was the set-partitioning constraint only variables which are not in this constraint could be fixed
3767        *       to zero, and this also means that the overlapping variables in this particular case are still active or
3768        *       fixed to 1
3769        *       later on it could be possible that even variables in cons are fixed to zero, which can lead to wrong
3770        *       results when checking if countofoverlapping[c] + consdata1->nfixedzeros == nvars1, because a fixed
3771        *       variable could be counted twice
3772        */
3773       else if( (!overlapdestroyed && countofoverlapping[c] + consdata1->nfixedzeros == nvars1) || countofoverlapping[c] == nvars1 )
3774       {
3775 	 /* even in deleted constraints we may fix unfixed variables */
3776 	 if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
3777 	 {
3778 	    const int oldnfixedvars = *nfixedvars;
3779 #ifndef NDEBUG
3780 	    SCIP_Bool negated0;
3781 	    SCIP_Bool negated1;
3782 #endif
3783 	    /* both constraints should stay merged */
3784 	    assert(consdata->merged);
3785 	    assert(consdata1->merged);
3786 
3787 	    vars1 = consdata1->vars;
3788 
3789 	    /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3790 	    SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3791 	    /* standard setppc-sorting now lost */
3792 	    consdata1->sorted = FALSE;
3793 
3794 	    /* iterate over the both cliques variables the "same" time */
3795 	    for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3796 	    {
3797 	       if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3798 	       {
3799 		  --v1;
3800 		  continue;
3801 	       }
3802 	       if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3803 	       {
3804 		  --v;
3805 		  continue;
3806 	       }
3807 
3808 	       /* all variables inside the second clique constraint should be either active or negated of an active one */
3809 	       assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3810 	       /* all variables inside the first clique constraint should be either active or negated of an active one */
3811 	       assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
3812 
3813 	       /* get not negated variable and clique value in cons */
3814 	       if( SCIPvarIsActive(vars[v]) )
3815 	       {
3816 		  var = vars[v];
3817 #ifndef NDEBUG
3818 		  negated0 = FALSE;
3819 #endif
3820 	       }
3821 	       else
3822 	       {
3823 		  assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])));
3824 		  var = SCIPvarGetNegationVar(vars[v]);
3825 #ifndef NDEBUG
3826 		  negated0 = TRUE;
3827 #endif
3828 	       }
3829 
3830 	       /* get active variable and clique value of next variable */
3831 	       if( SCIPvarIsActive(vars1[v1]) )
3832 	       {
3833 		  var1 = vars1[v1];
3834 #ifndef NDEBUG
3835 		  negated1 = FALSE;
3836 #endif
3837 	       }
3838 	       else
3839 	       {
3840 		  assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])));
3841 		  var1 = SCIPvarGetNegationVar(vars1[v1]);
3842 #ifndef NDEBUG
3843 		  negated1 = TRUE;
3844 #endif
3845 	       }
3846 
3847 	       /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
3848 	       if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1)  )
3849 	       {
3850 		  SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(var));
3851 
3852 		  /* fix all variables except the one which has the negated var in the clique to zero */
3853 		  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3854 		  if( *cutoff )
3855 		  {
3856 		     SCIPdebugMsg(scip, "fixing led to cutoff\n");
3857 
3858 		     return SCIP_OKAY;
3859 		  }
3860 
3861 		  assert(fixed);
3862 		  ++(*nfixedvars);
3863 
3864 		  --v;
3865 	       }
3866 	       /* variable index in the constraint is greater than the other one, so fix this variable */
3867 	       else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1)  )
3868 		  --v1;
3869 	       else
3870 	       {
3871 		  /* because the constraint's are merged it is not possible that one constraint contains a negated
3872 		   * variable of another and because all variables in cons1 are in cons this should be really the same
3873 		   * variable here; so we can decrease v and v1
3874 		   */
3875 		  assert(negated0 == negated1);
3876 
3877 		  --v;
3878 		  --v1;
3879 	       }
3880 	    }
3881 
3882 	    /* maybe we ended because of cons1(v1 reached -1) so try to add rest of cons to cons1 */
3883 	    for( ; v >= 0; --v)
3884 	    {
3885 	       if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3886 		  continue;
3887 
3888 	       SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars[v]));
3889 
3890 	       /* fix all variables except the one which has the negated var in the clique to zero */
3891 	       SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3892 	       if( *cutoff )
3893 	       {
3894 		  SCIPdebugMsg(scip, "fixing led to cutoff\n");
3895 
3896 		  return SCIP_OKAY;
3897 	       }
3898 
3899 	       assert(fixed);
3900 	       ++(*nfixedvars);
3901 	    }
3902 
3903 	    /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was
3904 	     * fixed to one, it's infeasible */
3905 	    if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros == nvars && consdata->nfixedones != 1 ) /*lint !e641*/
3906 	    {
3907 	       SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1));
3908 	       *cutoff = TRUE;
3909 
3910 	       return SCIP_OKAY;
3911 	    }
3912 
3913 	    /* could already be deleted because the constraint was included in another set partition constraint */
3914 	    if( SCIPconsIsActive(cons) )
3915 	    {
3916 	       /* delete cons because it include another set partitioning constraint */
3917 	       SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c);
3918 	       assert(SCIPconsIsActive(cons));
3919 
3920                SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) );
3921 	       SCIP_CALL( SCIPdelCons(scip, cons) );
3922 	       ++(*ndelconss);
3923 	    }
3924 
3925 	    /* due to fixings in cons0 mark overlapping invalid for checking with fixedzero variables together */
3926 	    if( oldnfixedvars < *nfixedvars )
3927 	       overlapdestroyed = TRUE;
3928 	 }
3929 	 else
3930 	 {
3931 	    assert(consdata1->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
3932 
3933 	    /* delete cons1 due to redundancy to cons */
3934 	    SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx);
3935 	    assert(SCIPconsIsActive(cons1));
3936 
3937             SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
3938 	    SCIP_CALL( SCIPdelCons(scip, cons1) );
3939 	    ++(*ndelconss);
3940 	 }
3941       }
3942       /* if cons has only one unfixed variable which is not in cons1 and cons1 has one variable which does not appear in
3943        * cons and both constraints are setpartitioning constraints we might aggregate both not overlapping variables and
3944        * delete one constraint
3945        */
3946       else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1 && countofoverlapping[c] == nvars1 - 1 ) /*lint !e641*/
3947       {
3948 	 SCIP_VAR* aggvar1;
3949 	 SCIP_VAR* aggvar2;
3950 	 SCIP_Bool negated0;
3951 	 SCIP_Bool negated1;
3952 
3953 	 aggvar1 = NULL;
3954 	 aggvar2 = NULL;
3955 
3956 	 /* both constraints should stay merged */
3957 	 assert(consdata->merged);
3958 	 assert(consdata1->merged);
3959 
3960 	 vars1 = consdata1->vars;
3961 
3962 	 /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3963 	 SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3964 	 /* standard setppc-sorting now lost */
3965 	 consdata1->sorted = FALSE;
3966 
3967 	 /* iterate over the both cliques variables the "same" time */
3968 	 for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3969 	 {
3970 	    if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3971 	    {
3972 	       --v1;
3973 	       continue;
3974 	    }
3975 	    if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3976 	    {
3977 	       --v;
3978 	       continue;
3979 	    }
3980 
3981 	    /* all variables inside the second clique constraint should be either active or negated of an active one */
3982 	    assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3983 	    /* all variables inside the first clique constraint should be either active or negated of an active one */
3984 	    assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
3985 
3986 	    /* get not negated variable and clique value in cons */
3987 	    if( SCIPvarIsActive(vars[v]) )
3988 	    {
3989 	       var = vars[v];
3990 	       negated0 = FALSE;
3991 	    }
3992 	    else
3993 	    {
3994 	       assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])));
3995 	       var = SCIPvarGetNegationVar(vars[v]);
3996 	       negated0 = TRUE;
3997 	    }
3998 
3999 	    /* get active variable and clique value of next variable */
4000 	    if( SCIPvarIsActive(vars1[v1]) )
4001 	    {
4002 	       var1 = vars1[v1];
4003 	       negated1 = FALSE;
4004 	    }
4005 	    else
4006 	    {
4007 	       assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])));
4008 	       var1 = SCIPvarGetNegationVar(vars1[v1]);
4009 	       negated1 = TRUE;
4010 	    }
4011 
4012 	    /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4013 	    if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1)  )
4014 	    {
4015 	       assert(aggvar1 == NULL);
4016 	       aggvar1 = vars[v];
4017 
4018 	       if( aggvar2 != NULL )
4019 		  break;
4020 
4021 	       --v;
4022 	    }
4023 	    /* variable index in the constraint is greater than the other one, so fix this variable */
4024 	    else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1)  )
4025 	    {
4026 	       assert(aggvar2 == NULL);
4027 	       aggvar2 = vars1[v1];
4028 
4029 	       if( aggvar1 != NULL )
4030 		  break;
4031 
4032 	       --v1;
4033 	    }
4034 	    else
4035 	    {
4036 	       /* because the constraint's are merged it is not possible that one constraint contains a negated variable
4037 		* of another, but both variables in both constraints still can be negated to each other
4038 		*/
4039 	       if( negated0 != negated1 )
4040 	       {
4041 		  /* cons is except for one variable equal to cons1 and the unequal variable in cons is negated
4042 		   * to the one in cons1, so the problem is infeasible
4043 		   */
4044 		  SCIPdebugMsg(scip, "two set-partitioning constraint <%s> and <%s> have only one variable not in common, but this variable <%s> appears in one constraint as the negated version as in the other constraint\n", SCIPconsGetName(cons), SCIPconsGetName(cons1), SCIPvarGetName(vars[v]));
4045 		  *cutoff = TRUE;
4046 
4047 		  return SCIP_OKAY;
4048 	       }
4049 	       --v;
4050 	       --v1;
4051 	    }
4052 	 }
4053 
4054 	 /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */
4055 	 if( aggvar1 == NULL && aggvar2 == NULL )
4056 	    continue;
4057 
4058 	 /* determine second aggregation var, if not yet done */
4059 	 if( aggvar2 == NULL )
4060 	 {
4061 	    for( ; v1 >= 0; --v1)
4062 	    {
4063 	       if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
4064 		  continue;
4065 
4066 	       aggvar2 = vars1[v1];
4067 	       break;
4068 	    }
4069 	 }
4070 	 /* determine first aggregation var, if not yet done */
4071 	 else if( aggvar1 == NULL )
4072 	 {
4073 	    /* maybe we ended because of cons1(v1 reached -1) so find the aggvar1 in cons */
4074 	    for( ; v >= 0; --v)
4075 	    {
4076 	       if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
4077 		  continue;
4078 
4079 	       aggvar1 = vars[v];
4080 	       break;
4081 	    }
4082 	 }
4083 
4084 	 /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */
4085 	 if( aggvar1 == NULL || aggvar2 == NULL )
4086 	    continue;
4087 
4088 	 SCIPdebugMsg(scip, "memorize the aggregation of <%s> == <%s>, because they are the last two variable which are different in these two set partitioning constraints <%s> <%s>\n", SCIPvarGetName(aggvar1), SCIPvarGetName(aggvar2), SCIPconsGetName(cons), SCIPconsGetName(cons1));
4089 
4090 	 /* resize the aggregation arrays if necessary */
4091 	 if( *saggregations == *naggregations )
4092 	 {
4093 	    *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1);
4094 	    assert(*saggregations > *naggregations);
4095 	    SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) );
4096 	    SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) );
4097 
4098 	    /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */
4099 	    BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/
4100 	 }
4101 
4102 	 /* memorize aggregation variables*/
4103 	 undoneaggrtypes[*naggregations] = TRUE;
4104 	 undoneaggrvars[2 * (*naggregations)] = aggvar1;
4105 	 undoneaggrvars[2 * (*naggregations) + 1] = aggvar2;
4106 	 ++(*naggregations);
4107 
4108 	 if( !SCIPdoNotAggr(scip) )
4109 	 {
4110 	    /* delete constraint */
4111 	    SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it is dominated by constraint <%s>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons));
4112 	    assert(SCIPconsIsActive(cons1));
4113 
4114             SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
4115 	    SCIP_CALL( SCIPdelCons(scip, cons1) );
4116 	    ++(*ndelconss);
4117 	 }
4118       }
4119       /* w.l.o.g. cons is a setpartitioning constraint and countofoverlapping == nvars - oldnfixedzeros - 1 we can
4120        * delete all overlapping variables in cons1 and add the negated variable of the not overlapped variable to cons
4121        * 1; the result should be a shorter constraint with the same impact
4122        */
4123       else if( shrinking && !overlapdestroyed && countofoverlapping[c] > 1 && ((consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1) || (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars1 - 1)) ) /*lint !e641*/
4124       {
4125 	 SCIP_CONSDATA* consdatachange;
4126 	 SCIP_VAR** varstostay;
4127 	 SCIP_VAR** varstochange;
4128 	 SCIP_CONS* constochange;
4129 	 SCIP_CONS* constostay;
4130 	 SCIP_VAR* addvar;
4131 	 SCIP_Bool negated0;
4132 	 SCIP_Bool negated1;
4133 	 int nvarstostay;
4134 	 int nvarstochange;
4135 	 int constochangeidx;
4136 #ifndef NDEBUG
4137 	 const int oldnchgcoefs = *nchgcoefs;
4138 #endif
4139 
4140 	 addvar = NULL;
4141 
4142 	 assert((consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING) != (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING) || countofoverlapping[c] != nvars - 1 || countofoverlapping[c] != nvars1 - 1); /*lint !e641*/
4143 
4144 	 /* both constraints should stay merged */
4145 	 assert(consdata->merged);
4146 	 assert(consdata1->merged);
4147 
4148 	 /* sorting array after indices of variables, negated and active counterparts would stand side by side */
4149 	 SCIPsortDownPtr((void**)(consdata1->vars), SCIPvarCompActiveAndNegated, nvars1);
4150 	 /* standard setppc-sorting now lost */
4151 	 consdata1->sorted = FALSE;
4152 
4153 	 /* initialize variables */
4154 	 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1) /*lint !e641*/
4155 	 {
4156 	    varstostay = vars;
4157 	    varstochange = consdata1->vars;
4158 	    nvarstostay = nvars;
4159 	    nvarstochange = nvars1;
4160 	    constostay = cons;
4161 	    constochange = cons1;
4162 	    consdatachange = consdata1;
4163 	    constochangeidx = c;
4164 	 }
4165 	 else
4166 	 {
4167 	    varstostay = consdata1->vars;
4168 	    varstochange = vars;
4169 	    nvarstostay = nvars1;
4170 	    nvarstochange = nvars;
4171 	    constostay = cons1;
4172 	    constochange = cons;
4173 	    consdatachange = consdata;
4174 	    constochangeidx = considx;
4175 
4176 	    *chgcons = TRUE;
4177 	 }
4178 
4179 	 /* iterate over the both cliques variables the "same" time, here we need the backward loop, because we
4180 	  * delete some variables and we don not want to loose order
4181 	  */
4182 	 for( v = nvarstostay - 1, v1 = nvarstochange - 1; v >= 0 && v1 >= 0; )
4183 	 {
4184 	    if( SCIPvarGetLbLocal(varstochange[v1]) > 0.5 || SCIPvarGetUbLocal(varstochange[v1]) < 0.5 )
4185 	    {
4186 	       --v1;
4187 	       continue;
4188 	    }
4189 	    if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 )
4190 	    {
4191 	       --v;
4192 	       continue;
4193 	    }
4194 
4195 	    /* all variables inside the second clique constraint should be either active or negated of an active one */
4196 	    assert(SCIPvarIsActive(varstochange[v1]) || (SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1]))));
4197 	    /* all variables inside the first clique constraint should be either active or negated of an active one */
4198 	    assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v]))));
4199 
4200 	    /* get not negated variable and clique value in constostay */
4201 	    if( SCIPvarIsActive(varstostay[v]) )
4202 	    {
4203 	       var = varstostay[v];
4204 	       negated0 = FALSE;
4205 	    }
4206 	    else
4207 	    {
4208 	       assert(SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v])));
4209 	       var = SCIPvarGetNegationVar(varstostay[v]);
4210 	       negated0 = TRUE;
4211 	    }
4212 
4213 	    /* get active variable and clique value of in constochange*/
4214 	    if( SCIPvarIsActive(varstochange[v1]) )
4215 	    {
4216 	       var1 = varstochange[v1];
4217 	       negated1 = FALSE;
4218 	    }
4219 	    else
4220 	    {
4221 	       assert(SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1])));
4222 	       var1 = SCIPvarGetNegationVar(varstochange[v1]);
4223 	       negated1 = TRUE;
4224 	    }
4225 
4226 	    /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4227 	    if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1)  )
4228 	    {
4229 	       assert(addvar == NULL);
4230 	       addvar = varstostay[v];
4231 	       --v;
4232 	    }
4233 	    /* variable index in the constraint is greater than the other one, so fix this variable */
4234 	    else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1)  )
4235 	    {
4236 	       --v1;
4237 	    }
4238 	    else
4239 	    {
4240 	       /* because the constraint's are merged it is not possible that one constraint contains a negated variable
4241 		* of another, but both constraint might have a variable in negated form of the other
4242 		*/
4243 	       if( negated0 != negated1 )
4244 	       {
4245 		  assert(addvar == NULL);
4246 
4247 		  SCIPdebugMsg(scip, "-> trying to fix <%s> to 0 because it would exist twice in a constraint\n", SCIPvarGetName(varstochange[v1]));
4248 
4249 		  /* fix variable to zero */
4250 		  SCIP_CALL( SCIPfixVar(scip, varstochange[v1], 0.0, cutoff, &fixed) );
4251 		  if( *cutoff )
4252 		  {
4253 		     SCIPdebugMsg(scip, "fixing led to cutoff\n");
4254 
4255 		     return SCIP_OKAY;
4256 		  }
4257 
4258 		  assert(fixed);
4259 		  ++(*nfixedvars);
4260 
4261 		  /* the above fixing is equal to the fixation of varstostay[v] to 1, so we can call presolvePropagateCons() for consstay */
4262 		  SCIP_CALL( presolvePropagateCons(scip, constostay, FALSE, NULL, NULL, NULL, NULL, nfixedvars, naggrvars, ndelconss, cutoff) );
4263 
4264 		  return SCIP_OKAY;
4265 	       }
4266 	       else
4267 	       {
4268 		  /* correct local data structure, remove variable from constraint entry where it will be removed */
4269 		  deleteCliqueDataEntry(varstochange[v1], constochangeidx, vartoindex, varnconss, varconsidxs);
4270 
4271 		  SCIPdebugMsg(scip, " -> deleting variable <%s> in constraint <%s> number %d, because it will be replaced\n", SCIPvarGetName(varstochange[v1]), SCIPconsGetName(constochange), constochangeidx);
4272 		  /* delete overlapping variables in constochange */
4273 		  SCIP_CALL( delCoefPos(scip, constochange, v1) );
4274 		  ++(*nchgcoefs);
4275 	       }
4276 
4277 	       --v;
4278 	       --v1;
4279 	    }
4280 	 }
4281 	 assert(addvar != NULL || v >= 0);
4282 	 /* we should have removed exactly countofoverlapping[c] variables from the constochange */
4283 	 assert(*nchgcoefs - oldnchgcoefs == countofoverlapping[c]);
4284 
4285 	 /* determine addvar if not yet found */
4286 	 if( addvar == NULL )
4287 	 {
4288 	    for( ; v >= 0; --v)
4289 	    {
4290 	       if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 )
4291 		  continue;
4292 
4293 	       /* all variables inside the first clique constraint should be either active or negated of an active one */
4294 	       assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v]))));
4295 
4296 	       addvar = varstostay[v];
4297 	       break;
4298 	    }
4299 	 }
4300 	 assert(addvar != NULL);
4301 
4302 	 /* get representative variable for all deleted variables */
4303 	 SCIP_CALL( SCIPgetNegatedVar(scip, addvar, &addvar) );
4304 	 assert(addvar != NULL);
4305 
4306 	 SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(constochange), constochangeidx);
4307 	 /* add representative for overlapping instead */
4308 	 SCIP_CALL( addCoef(scip, constochange, addvar) );
4309 	 ++(*nchgcoefs);
4310 
4311 	 /* constraint should be still merged because this added variable is new in this constraint */
4312 	 consdatachange->merged = TRUE;
4313 	 assert(constochangeidx == (cons == constochange ? considx : c));
4314 
4315 	 /* correct local data structure, add constraint entry to variable data  */
4316 	 SCIP_CALL( addCliqueDataEntry(scip, addvar, constochangeidx, TRUE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4317 
4318 	 /* cons changed so much, that it cannot be used for more overlapping checks */
4319 	 if( *chgcons )
4320 	    return SCIP_OKAY;
4321       }
4322    }
4323 
4324    return SCIP_OKAY;
4325 }
4326 
4327 /** try to lift variables to given constraint */
4328 /** @todo try another variant by determine lifting variables as the intersection of all cliques variables of the
4329  *        constraint variables, note that the intersection changes after one variable was added
4330  */
4331 static
liftCliqueVariables(SCIP * const scip,SCIP_CONS * const cons,int const arraypos,SCIP_VAR ** const usefulvars,int * const nusefulvars,int const endidx,SCIP_Bool ** cliquevalues,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs,int * const maxnvars,int * const nadded,SCIP_Bool * const chgcons,int * const nfixedvars,int * const ndelconss,SCIP_Bool * const cutoff)4332 SCIP_RETCODE liftCliqueVariables(
4333    SCIP*const            scip,               /**< SCIP data structure */
4334    SCIP_CONS*const       cons,               /**< constraint which may overlap */
4335    int const             arraypos,           /**< position of constraint in global array */
4336    SCIP_VAR**const       usefulvars,         /**< possible variables to lift */
4337    int*const             nusefulvars,        /**< pointer to store number of added variables */
4338    int const             endidx,             /**< end index for possible lifting variables */
4339    SCIP_Bool**           cliquevalues,       /**< pointer to clique values of constraint-variables, either one if the
4340 					      *   variable is active or zero if the variable is negated
4341 					      *   @note this array can be resized in this method
4342 					      */
4343    SCIP_HASHMAP*const    vartoindex,         /**< hashmap mapping variables to indices */
4344    int*const             varnconss,          /**< array with number of constraints a variable occurs */
4345    int*const             maxnvarconsidx,     /**< array with the maximal number of occurrences of a variable */
4346    int**const            varconsidxs,        /**< array with constraint indices in which the corresponding variable
4347 					      *   exists
4348 					      */
4349    int*const             maxnvars,           /**< pointer to store maximal number of variables of a constraint */
4350    int*const             nadded,             /**< pointer to store number of possible added variables */
4351    SCIP_Bool*const       chgcons,            /**< pointer to store if the constraint was changed, due to added
4352 					      *   variables
4353 					      */
4354    int*const             nfixedvars,         /**< pointer to count number of deleted variables */
4355    int*const             ndelconss,          /**< pointer to count number of deleted constraints */
4356    SCIP_Bool*const       cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
4357    )
4358 {
4359    SCIP_CONSDATA* consdata;
4360    SCIP_VAR** vars;
4361    SCIP_VAR* var;
4362    SCIP_VAR* var1;
4363    SCIP_Bool fixed;
4364    SCIP_Bool value;
4365    int nvars;
4366    int nottocheck; /* will be the position for a variable in cons0 which is in negated form in the same clique */
4367    int v;
4368    int v1;
4369    int k;
4370 
4371    assert(scip != NULL);
4372    assert(cons != NULL);
4373    assert(usefulvars != NULL);
4374    assert(cliquevalues != NULL);
4375    assert(*cliquevalues != NULL);
4376    assert(vartoindex != NULL);
4377    assert(varnconss != NULL);
4378    assert(maxnvarconsidx != NULL);
4379    assert(varconsidxs != NULL);
4380    assert(maxnvars != NULL);
4381    assert(nadded != NULL);
4382    assert(chgcons != NULL);
4383    assert(nfixedvars != NULL);
4384    assert(ndelconss != NULL);
4385    assert(cutoff != NULL);
4386 
4387    if( !SCIPconsIsActive(cons) )
4388       return SCIP_OKAY;
4389 
4390    consdata = SCIPconsGetData(cons);
4391    assert(consdata != NULL);
4392 
4393    nvars = consdata->nvars;
4394 
4395    if( nvars == 0 )
4396       return SCIP_OKAY;
4397 
4398    assert(nvars <= *maxnvars);
4399 
4400    vars = consdata->vars;
4401    assert(vars != NULL);
4402 
4403    v1 = endidx;
4404 
4405    /* now we try to add variables with index prior to endidx to cons */
4406    for( v = nvars - 1; v >= 0 && v1 >= 0; )
4407    {
4408       if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 )
4409       {
4410 	 --v1;
4411 	 continue;
4412       }
4413       if( SCIPvarGetUbLocal(vars[v]) < 0.5 )
4414       {
4415 	 --v;
4416 	 continue;
4417       }
4418 
4419       /* check that constraint variables are still correctly sorted, indices of active variables should be decreasing */
4420       assert(v == 0 || SCIPvarCompareActiveAndNegated(vars[v], vars[v - 1]) <= 0);
4421 
4422       /* there should no variables fixed to one occur in our constraint */
4423       assert(SCIPvarGetLbLocal(vars[v]) < 0.5 && SCIPvarGetUbLocal(vars[v]) > 0.5);
4424       assert(SCIPvarGetLbLocal(usefulvars[v1]) < 0.5 && SCIPvarGetUbLocal(usefulvars[v1]) > 0.5);
4425 
4426       /* all variables which we have inside the clique constraint and which can possibly be added should be either active or negated */
4427       assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
4428       assert(SCIPvarIsActive(usefulvars[v1]) || (SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1]))));
4429 
4430       /* constraint should during adding of variables stay merged, because for each variable which is added holds that
4431        * the index of this corresponding active variable is pairwise different to all indices of all active
4432        * corresponding variables inside the constraint
4433        * @note it should not happen that we add one variable and the corresponding counterpart to the same constraint */
4434       assert(consdata->merged);
4435 
4436       /* get active variable and clique value in cons */
4437       if( (*cliquevalues)[v] )
4438 	 var = vars[v];
4439       else
4440       {
4441 	 assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])));
4442 	 var = SCIPvarGetNegationVar(vars[v]);
4443       }
4444 
4445       /* get active variable and clique value of next variable */
4446       if( SCIPvarIsActive(usefulvars[v1]) )
4447       {
4448 	 var1 = usefulvars[v1];
4449 	 value = TRUE;
4450       }
4451       else
4452       {
4453 	 assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1])));
4454 	 var1 = SCIPvarGetNegationVar(usefulvars[v1]);
4455 	 value = FALSE;
4456       }
4457 
4458       nottocheck = -1;
4459       k = 0;
4460 
4461       /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4462       if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1)  )
4463       {
4464 	 --v;
4465 	 continue;
4466       }
4467       /* variable index in the constraint is greater than the other one, so check for possible inclusion of the variable */
4468       else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1)  )
4469       {
4470 	 assert(consdata == SCIPconsGetData(cons));
4471 
4472 	 /* check if every variable in the actual clique is in clique with the new variable */
4473 	 for( k = nvars - 1; k >= 0; --k )
4474 	 {
4475 	    if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4476 	    {
4477 	       /* there should no variables fixed to one occur in our constraint */
4478 	       assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4479 	       assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4480 
4481 	       if( (*cliquevalues)[k] )
4482 	       {
4483 		  assert(SCIPvarIsActive(vars[k]));
4484 		  var = vars[k];
4485 	       }
4486 	       else
4487 	       {
4488 		  assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])));
4489 		  var = SCIPvarGetNegationVar(vars[k]);
4490 	       }
4491 	       if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) )
4492 		  break;
4493 	    }
4494 	 }
4495 	 --v1;
4496       }
4497       /* variable index in the constraint is equal to the index of the other variable, check if these variables are
4498        * negated of each other so memorize the position and check for possible inclusion of the new variable and if
4499        * possible decrease indices
4500        */
4501       else
4502       {
4503 	 /* one clique contains the negated and the other clique the corresponding active var */
4504 	 if( value != (*cliquevalues)[v] )
4505 	 {
4506 	    nottocheck = v;
4507 
4508 	    assert(consdata == SCIPconsGetData(cons));
4509 	    assert(nvars <= consdata->nvars);
4510 
4511 	    /* check if every variable in the actual clique is in clique with the new variable */
4512 	    for( k = nvars - 1; k >= 0; --k )
4513 	    {
4514 	       if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4515 	       {
4516 		  /* there should no variables fixed to one occur in our constraint */
4517 		  assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4518 
4519 		  assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4520 
4521 		  if( k == nottocheck )
4522 		     continue;
4523 
4524 		  if( (*cliquevalues)[k] )
4525 		  {
4526 		     assert(SCIPvarIsActive(vars[k]));
4527 		     var = vars[k];
4528 		  }
4529 		  else
4530 		  {
4531 		     assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])));
4532 		     var = SCIPvarGetNegationVar(vars[k]);
4533 		  }
4534 
4535 		  if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) )
4536 		     break;
4537 	       }
4538 	    }
4539 	 }
4540 	 /* don't decrease v because it might happen that the corresponding negated variable of var is next in
4541 	  * usefulvars
4542 	  */
4543 	 --v1;
4544       }
4545 
4546       /* if k is smaller than 0 than the possible new variables is in the same clique with all variables of cons,
4547        * so we add the new variable to clique constraint or fix some variables */
4548       if( k < 0 )
4549       {
4550 	 ++(*nadded);
4551 
4552 	 /* we found a variable which is the negated variable of another one in this clique so we can fix all
4553 	  * other variable to zero and if it's a partitioning constraint we can also fix the variable of the
4554 	  * negated to one and we can delete the constraint too */
4555 	 if( nottocheck >= 0 )
4556 	 {
4557 	    assert(consdata == SCIPconsGetData(cons));
4558 	    assert(nvars <= consdata->nvars);
4559 	    assert(consdata->merged);
4560 
4561 	    /* process all vars for possible fixing */
4562 	    for( k = consdata->nvars - 1; k >= 0; --k )
4563 	    {
4564 	       if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4565 	       {
4566 		  /* there should no variables fixed to one occur in our constraint */
4567 		  assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
4568 
4569 		  assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4570 
4571 		  if( k != nottocheck )
4572 		  {
4573 		     SCIPdebugMsg(scip, "trying to fix <%s> to 0 because we could lift a negated variable of another constraint variable\n", SCIPvarGetName(vars[k]));
4574 		     /* fix variable to zero */
4575 		     SCIP_CALL( SCIPfixVar(scip, vars[k], 0.0, cutoff, &fixed) );
4576 
4577 		     if( *cutoff )
4578 		     {
4579 			SCIPdebugMsg(scip, "fixing led to cutoff\n");
4580 
4581 			return SCIP_OKAY;
4582 		     }
4583 
4584 		     assert(fixed);
4585 
4586 		     ++(*nfixedvars);
4587 		  }
4588 	       }
4589 	    }
4590 	    if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4591 	    {
4592 	       assert(SCIPvarIsActive(vars[nottocheck]) || (SCIPvarGetStatus(vars[nottocheck]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[nottocheck]))));
4593 
4594 	       SCIPdebugMsg(scip, "trying to fix <%s> to 1 due to this setpartitioning variable is with its negated in the same clique\n", SCIPvarGetName(vars[nottocheck]));
4595 	       /* fix the remaining variable to one, due to it's the only one left to satisfy the constraint */
4596 	       SCIP_CALL( SCIPfixVar(scip, vars[nottocheck], 1.0, cutoff, &fixed) );
4597 	       if( *cutoff )
4598 	       {
4599 		  SCIPdebugMsg(scip, "fixing led to cutoff\n");
4600 
4601 		  return SCIP_OKAY;
4602 	       }
4603 
4604 	       assert(fixed);
4605 	       ++(*nfixedvars);
4606 	    }
4607 
4608 	    /* delete constraint */
4609 	    SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to active and negated variable in the same clique constraint\n", SCIPconsGetName(cons), arraypos);
4610 	    assert(SCIPconsIsActive(cons));
4611 	    SCIP_CALL( SCIPdelCons(scip, cons) );
4612 	    ++(*ndelconss);
4613 
4614 	    break;
4615 	 }
4616 	 /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */
4617 	 else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4618 	 {
4619 	    SCIPdebugMsg(scip, "trying to fix <%s> to 0 because this variable is in the same clique with a set partition\n", SCIPvarGetName(usefulvars[v1 + 1]));
4620 	    /* fix variable to zero */
4621 	    SCIP_CALL( SCIPfixVar(scip, usefulvars[v1 + 1], 0.0, cutoff, &fixed) );
4622 
4623 	    if( *cutoff )
4624 	    {
4625 	       SCIPdebugMsg(scip, "fixing led to cutoff\n");
4626 
4627 	       return SCIP_OKAY;
4628 	    }
4629 
4630 	    assert(fixed);
4631 
4632 	    ++(*nfixedvars);
4633 	 }
4634 	 /* we have found a new variable for a set packing constraint cons, so add the found variable to the first constraint */
4635 	 else
4636 	 {
4637 	    SCIP_VAR* addvar;
4638 
4639 	    assert(SCIPconsIsActive(cons));
4640 
4641 	    addvar = usefulvars[v1 + 1];
4642 
4643 	    assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
4644 
4645 	    /* add representative instead */
4646 	    SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(usefulvars[v1 + 1]), SCIPconsGetName(cons), arraypos);
4647 	    SCIP_CALL( addCoef(scip, cons, addvar) );
4648 	    assert(consdata == SCIPconsGetData(cons));
4649 	    /* we know that this constraint stays merged but later on we have to resort */
4650 	    consdata->merged = TRUE;
4651 
4652 	    /* second we add the constraint index to the list of indices where this variable occurs */
4653 	    assert(SCIPhashmapExists(vartoindex, (void*) addvar));
4654 
4655 	    /* correct local data structure, add constraint entry to variable data  */
4656 	    SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4657 
4658 	    /* we need the new pointer to the variables, because due to adding variables it is possible that we
4659 	     * did reallocate the variables array inside the constraint, the index v should stay the same because the
4660 	     * added variable was inserted at the end and we are decreasing v in our for loop
4661 	     */
4662 	    vars = consdata->vars;
4663 	    nvars = consdata->nvars;
4664 
4665 	    /* we need to update our data structure */
4666 
4667 	    /* resize clique array if necessary, due to adding variables */
4668 	    if( (*maxnvars) < nvars )
4669 	    {
4670 	       while( (*maxnvars) < nvars )
4671 		  (*maxnvars) *= 2 ;
4672 	       SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) );
4673 	    }
4674 	    (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE;
4675 
4676 	    (*chgcons) = TRUE;
4677 	 }
4678       }
4679    }
4680 
4681    if( !SCIPconsIsActive(cons) )
4682       return SCIP_OKAY;
4683 
4684    /* maybe we stopped because of cons(v reached -1) so try to add rest in usefulvars */
4685    for( ; v1 >= 0; --v1)
4686    {
4687       if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 )
4688 	 continue;
4689 
4690       /* get active variable and clique value */
4691       if( SCIPvarIsActive(usefulvars[v1]) )
4692       {
4693 	 var1 = usefulvars[v1];
4694 	 value = TRUE;
4695       }
4696       else
4697       {
4698 	 assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1])));
4699 	 var1 = SCIPvarGetNegationVar(usefulvars[v1]);
4700 	 value = FALSE;
4701       }
4702 
4703       assert(consdata == SCIPconsGetData(cons));
4704       assert(nvars <= consdata->nvars);
4705 
4706       /* check if every variable in the actual clique is in clique with the new variable */
4707       for( k = nvars - 1; k >= 0; --k )
4708       {
4709 	 if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4710 	 {
4711 	    /* there should no variables fixed to one occur in our constraint */
4712 	    assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4713 
4714 	    assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4715 
4716 	    if( (*cliquevalues)[k] )
4717 	    {
4718 	       assert(SCIPvarIsActive(vars[k]));
4719 	       var = vars[k];
4720 	    }
4721 	    else
4722 	    {
4723 	       assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])));
4724 	       var = SCIPvarGetNegationVar(vars[k]);
4725 	    }
4726 
4727 	    if( !SCIPvarsHaveCommonClique(var1, value, var, (*cliquevalues)[k], TRUE) )
4728 	       break;
4729 	 }
4730       }
4731 
4732       /* add new variable to clique constraint or fix some variables */
4733       if( k < 0 )
4734       {
4735 	 /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */
4736 	 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4737 	 {
4738 	    SCIPdebugMsg(scip, "trying to fix <%s> to 0 because this variable is in the same clique with a set partition\n", SCIPvarGetName(usefulvars[v1]));
4739 
4740 	    /* fix variable to zero */
4741 	    SCIP_CALL( SCIPfixVar(scip, usefulvars[v1], 0.0, cutoff, &fixed) );
4742 	    if( *cutoff )
4743 	    {
4744 	       SCIPdebugMsg(scip, "fixing led to cutoff\n");
4745 
4746 	       return SCIP_OKAY;
4747 	    }
4748 	    assert(fixed);
4749 
4750 	    ++(*nfixedvars);
4751 	    ++(*nadded);
4752 	 }
4753 	 /* add the found variable to the first constraint */
4754 	 else
4755 	 {
4756 	    SCIP_VAR* addvar;
4757 
4758 	    assert(SCIPconsIsActive(cons));
4759 
4760 	    addvar = usefulvars[v1];
4761 
4762 	    assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
4763 
4764 	    /* add representative instead */
4765 	    SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(cons), arraypos);
4766 	    SCIP_CALL( addCoef(scip, cons, addvar) );
4767 	    assert(consdata == SCIPconsGetData(cons));
4768 	    /* we know that this constraint stays merged but later on we have to resort */
4769 	    consdata->merged = TRUE;
4770 
4771 	    /* second we add the constraint index to the list of indices where this variable occurs */
4772 	    assert(SCIPhashmapExists(vartoindex, (void*) addvar));
4773 
4774 	    /* correct local data structure, add constraint entry to variable data  */
4775 	    SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4776 
4777 	    /* we need the new pointer to the variables, because due to adding variables it is possible that we
4778 	     * did reallocate the variables array inside the constraint, the index v should stay the same because the
4779 	     * added variable was inserted at the end and we are decreasing v in our for loop
4780 	     */
4781 	    vars = consdata->vars;
4782 	    nvars = consdata->nvars;
4783 
4784 	    /* we need to update our data structure */
4785 
4786 	    /* resize clique array if necessary, due to adding variables */
4787 	    if( (*maxnvars) < nvars )
4788 	    {
4789 	       while( (*maxnvars) < nvars )
4790 		  (*maxnvars) *= 2 ;
4791 	       SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) );
4792 	    }
4793 	    (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE;
4794 
4795 	    ++(*nadded);
4796 	    (*chgcons) = TRUE;
4797 	 }
4798       }
4799    }
4800 
4801    return SCIP_OKAY;
4802 }
4803 
4804 /** perform all collected aggregations */
4805 static
performAggregations(SCIP * const scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR ** const undoneaggrvars,SCIP_Bool * const undoneaggrtypes,int const naggregations,int * const naggrvars,SCIP_Bool * const cutoff)4806 SCIP_RETCODE performAggregations(
4807    SCIP*const            scip,               /**< SCIP data structure */
4808    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
4809    SCIP_VAR**const       undoneaggrvars,     /**< aggregation variables storage */
4810    SCIP_Bool*const       undoneaggrtypes,    /**< aggregation type storage, type FALSE means the aggregation is of the
4811 					      *   form x + y = 1; type TRUE means the aggregation is of the form x = y;
4812 					      */
4813    int const             naggregations,      /**< number of aggregations to performed */
4814    int*const             naggrvars,          /**< pointer to count number of aggregated variables */
4815    SCIP_Bool*const       cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
4816    )
4817 {  /*lint --e{715}*/
4818    SCIP_VAR* var1;
4819    SCIP_VAR* var2;
4820    SCIP_Bool aggregated;
4821    SCIP_Bool redundant;
4822    int a;
4823 
4824    assert(scip != NULL);
4825    assert(conshdlrdata != NULL);
4826    assert(undoneaggrvars != NULL);
4827    assert(undoneaggrtypes != NULL);
4828    assert(naggregations > 0);
4829    assert(naggrvars != NULL);
4830    assert(cutoff != NULL);
4831 
4832    /* loop over all open aggregations and try to aggregate them */
4833    for( a = 0; a < naggregations; ++a  )
4834    {
4835       var1 = undoneaggrvars[2 * a];
4836       var2 = undoneaggrvars[2 * a + 1];
4837       assert(var1 != NULL);
4838       assert(var2 != NULL);
4839 
4840       SCIPdebugMsg(scip, "trying to aggregate <%s> %s <%s>%s\n", SCIPvarGetName(var1), undoneaggrtypes[a] ? "=" : "+", SCIPvarGetName(var2), undoneaggrtypes[a] ? "" : " = 1");
4841 
4842 #ifdef VARUSES
4843       /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate,
4844        * and increase usage counting again
4845        */
4846       SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var1) );
4847       SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var2) );
4848 #endif
4849 
4850       /* aggregate last remaining variables in the set partitioning constraint */
4851       if( undoneaggrtypes[a] )
4852       {
4853 	 SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, -1.0, 0.0, cutoff, &redundant, &aggregated) );
4854       }
4855       else
4856       {
4857 	 SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) );
4858       }
4859 
4860       if( *cutoff )
4861       {
4862 	 SCIPdebugMsg(scip, "aggregation was infeasible\n");
4863 
4864 	 return SCIP_OKAY;
4865       }
4866       /* binary variables should always be aggregated, or due to fixation the aggregation is redundant */
4867       assert(redundant);
4868 
4869       if( aggregated )
4870 	 ++(*naggrvars);
4871 
4872 #ifdef VARUSES
4873       /* increase variable usage counting again */
4874       SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var1) );
4875       SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var2) );
4876 #endif
4877    }
4878 
4879    return SCIP_OKAY;
4880 }
4881 
4882 /** check whether we can combine or grow cliques so some constraints become redundant or we can fix variables */
4883 /** @todo try another variant, by building up the clique graph and delete unnecessary (transitive closure) edges and do
4884  *        a bfs search to search for common ancestors to get all possible lifting variables
4885  */
4886 static
preprocessCliques(SCIP * const scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONS ** const conss,int const nconss,int const nrounds,int * const firstchange,int * const firstclique,int * const lastclique,int * const nfixedvars,int * const naggrvars,int * const ndelconss,int * const nchgcoefs,SCIP_Bool * const cutoff)4887 SCIP_RETCODE preprocessCliques(
4888    SCIP*const            scip,               /**< SCIP data structure */
4889    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
4890    SCIP_CONS**const      conss,              /**< constraint set */
4891    int const             nconss,             /**< number of constraints in constraint set */
4892    int const             nrounds,            /**< actual presolving round */
4893    int*const             firstchange,        /**< pointer to store first changed constraint */
4894    int*const             firstclique,        /**< pointer to store first constraint to start adding clique again */
4895    int*const             lastclique,         /**< pointer to store last constraint to add cliques again */
4896    int*const             nfixedvars,         /**< pointer to count number of deleted variables */
4897    int*const             naggrvars,          /**< pointer to count number of aggregated variables */
4898    int*const             ndelconss,          /**< pointer to count number of deleted constraints */
4899    int*const             nchgcoefs,          /**< pointer to count number of deleted coefficients */
4900    SCIP_Bool*const       cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
4901    )
4902 {
4903    /* extend cliques/constraints by checking whether some variables are in the same clique, no pairwise clique lifting
4904     * which would be slower
4905     */
4906    SCIP_CONS** usefulconss;                  /* array with pointers of constraint of setpartitioning and setpacking type */
4907    SCIP_VAR** usefulvars;                    /* array with pointers of variables in setpartitioning and setpacking constraints */
4908    int** varconsidxs;                        /* array consisting of constraint indices in which the corresponding variable exists */
4909    int* varnconss;                           /* array consisting of number of constraints the variable occurs */
4910    int* maxnvarconsidx;                      /* maximal number of occurrences of a variable */
4911    int* countofoverlapping = NULL;           /* the amount of variables which are in another constraint */
4912    SCIP_Bool* cliquevalues = NULL;           /* values of clique-variables, either one if the variable is active or zero if the variable is negated */
4913 
4914    SCIP_HASHMAP* vartoindex;                 /* mapping of SCIP variables to indices */
4915    SCIP_CONSDATA* consdata;
4916 
4917    SCIP_Bool chgcons0;
4918    int nvars;
4919    int c;
4920    int v;
4921    int nusefulconss;
4922    int nusefulvars;
4923    int susefulvars;
4924    int maxnvars;
4925    int varindex;
4926 
4927    SCIP_VAR** undoneaggrvars;                /* storage for not yet performed aggregations */
4928    SCIP_Bool* undoneaggrtypes;               /* storage for not yet performed aggregation type (x = y or x + y = 1) */
4929    int saggregations;
4930    int naggregations;
4931 
4932    assert(scip != NULL);
4933    assert(conshdlrdata != NULL);
4934    assert(conss != NULL || nconss == 0);
4935    assert(firstchange != NULL);
4936    assert(firstclique != NULL);
4937    assert(lastclique != NULL);
4938    assert(nfixedvars != NULL);
4939    assert(naggrvars != NULL);
4940    assert(ndelconss != NULL);
4941    assert(nchgcoefs != NULL);
4942    assert(cutoff != NULL);
4943 
4944    *cutoff = FALSE;
4945 
4946    if( nconss == 0 )
4947       return SCIP_OKAY;
4948 
4949    nvars = SCIPgetNVars(scip);
4950 
4951    if( nvars == 0 )
4952       return SCIP_OKAY;
4953 
4954    susefulvars = 2 * nvars; /* two times because of negated vars, maybe due to deleted variables we need to increase this */
4955 
4956    /* a hashmap from varindex to postion in varconsidxs array, because above is still too small */
4957    SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nvars) );
4958 
4959    /* get temporary memory for the aggregation storage, to memorize aggregations which will be performed later, otherwise we would destroy our local data structures */
4960    saggregations = nvars;
4961    SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrvars, 2 * saggregations) );
4962    SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrtypes, saggregations) );
4963    BMSclearMemoryArray(undoneaggrtypes, saggregations);
4964    naggregations = 0;
4965 
4966    /* get temporary memory for all clique constraints, all appearing variables and the mapping from variables to constraints */
4967    SCIP_CALL( SCIPallocBufferArray(scip, &usefulconss, nconss) );
4968    SCIP_CALL( SCIPallocBufferArray(scip, &usefulvars, susefulvars) );
4969    BMSclearMemoryArray(usefulvars, susefulvars);
4970    SCIP_CALL( SCIPallocBufferArray(scip, &varnconss, susefulvars + 1) );
4971    BMSclearMemoryArray(varnconss, susefulvars + 1);
4972    SCIP_CALL( SCIPallocBufferArray(scip, &maxnvarconsidx, susefulvars + 1) );
4973    SCIP_CALL( SCIPallocBufferArray(scip, &varconsidxs, susefulvars + 1) );
4974    BMSclearMemoryArray(varconsidxs, susefulvars + 1);
4975    nusefulvars = 0;
4976    nusefulconss = 0;
4977    maxnvars = 0;
4978 
4979    /* @todo: check for round limit for adding extra clique constraints */
4980    /* adding clique constraints which arises from global clique information */
4981    if( conshdlrdata->nclqpresolve == 0 && conshdlrdata->addvariablesascliques )
4982    {
4983       SCIP_VAR** vars = SCIPgetVars(scip);
4984       SCIP_VAR** binvars;
4985       int* cliquepartition;
4986       int ncliques;
4987       int nbinvars;
4988       int naddconss;
4989 
4990       nbinvars = SCIPgetNBinVars(scip);
4991       SCIP_CALL( SCIPduplicateBufferArray(scip, &binvars, vars, nbinvars) );
4992       SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nbinvars) );
4993 
4994       /* @todo: check for better permutations/don't permute the first round
4995        * @todo: take binary variables which are not of vartype SCIP_VARTYPE_BINARY into account
4996        */
4997       SCIPrandomPermuteArray(conshdlrdata->randnumgen, (void**)binvars, 0, nbinvars);
4998 
4999       /* try to create a clique-partition over all binary variables and create these cliques as new setppc constraints
5000        * and add them to the usefulconss array and adjust all necessary data this will hopefully lead to faster
5001        * detection of redundant constraints
5002        */
5003       SCIP_CALL( SCIPcalcCliquePartition(scip, binvars, nbinvars, cliquepartition, &ncliques) );
5004 
5005       /* resize usefulconss array if necessary */
5006       SCIP_CALL( SCIPreallocBufferArray(scip, &usefulconss, nconss + ncliques) );
5007 
5008       naddconss = 0;
5009 
5010       /* add extra clique constraints resulting from the cliquepartition calculation to SCIP and to the local data structure */
5011       SCIP_CALL( addExtraCliques(scip, binvars, nbinvars, cliquepartition, ncliques, usefulconss, &nusefulconss,
5012             nrounds, nfixedvars, &naddconss, ndelconss, nchgcoefs, cutoff) );
5013 
5014       /* bad hack, we don't want to count these artificial created constraints if they got deleted, so ndelconss
5015        * can become negative which will be change to zero at the end of this method if it's still negative
5016        */
5017       *ndelconss -= naddconss;
5018 
5019       SCIPfreeBufferArray(scip, &cliquepartition);
5020       SCIPfreeBufferArray(scip, &binvars);
5021 
5022       if( *cutoff )
5023 	 goto TERMINATE;
5024    }
5025 
5026    /* start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these
5027     * constraints
5028     */
5029    SCIP_CALL( collectCliqueConss(scip, conss, nconss, usefulconss, &nusefulconss, nfixedvars, ndelconss, nchgcoefs, cutoff) );
5030    /* @Note: Even after the call above some constraints can have fixed variables, because it might happen that caused by
5031     * mergeMultiplies some variables were fixed which occurred already in previous constraints
5032     */
5033    if( *cutoff )
5034       goto TERMINATE;
5035 
5036    /* no usefulconss found */
5037    if( nusefulconss <= 1 )
5038       goto TERMINATE;
5039 
5040    /* @todo: maybe sort them after biggest indices too, or another variant would be to restore the order as they were
5041     *        read in
5042     */
5043    /* sort constraints first after type (partitioning before packing) and second after number of variables such that the
5044     * partitioning constraints have increasing number of variables and the packing constraints have decreasing number of
5045     * variables, because we loop from back to front we sort them downwards, so they are the other way around
5046     */
5047    SCIPsortDownPtr((void**)usefulconss, setppcConssSort, nusefulconss);
5048 
5049    /* creating all necessary data in array structure, collect all clique constraint variables and occurrences */
5050    SCIP_CALL( collectCliqueData(scip, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs, &maxnvars) );
5051    assert(maxnvars > 0);
5052 
5053    /* allocate temporary memory for actual clique */
5054    SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, maxnvars) );
5055    /* allocate temporary memory for counting an overlap of variables */
5056    SCIP_CALL( SCIPallocBufferArray(scip, &countofoverlapping, nusefulconss) );
5057 
5058    /* sort usefulvars after indices of variables, negated and active counterparts will stand side by side */
5059    SCIPsortDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, nusefulvars);
5060 
5061    /* extend cliques/constraints by checking whether some variables of a second constraint are in the same clique */
5062    for( c = nusefulconss - 1; c >= 0 && !SCIPisStopped(scip); --c )
5063    {
5064       SCIP_VAR** cons0vars;                  /* these are the clique variables */
5065       SCIP_CONS* cons0;
5066       int ncons0vars;
5067       SCIP_VAR* var0;
5068       int v1;
5069       int nadded;     /* number of possible added variables to constraint */
5070       int cons0fixedzeros;
5071       int oldnchgcoefs;
5072 #ifndef NDEBUG
5073       const int oldnaggrvars = *naggrvars;
5074 #endif
5075       cons0 = usefulconss[c];
5076 
5077       if( !SCIPconsIsActive(cons0) )
5078          continue;
5079 
5080       /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
5081        * possible
5082        */
5083       SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
5084 
5085       if( *cutoff )
5086 	 break;
5087 
5088       /* we can't handle aggregated variables later on so we should have saved them for later */
5089       assert(*naggrvars == oldnaggrvars);
5090 
5091       if( !SCIPconsIsActive(cons0) )
5092          continue;
5093 
5094       /* we need to determine the cliquedata in each iteration because we eventual will change it later */
5095       consdata = SCIPconsGetData(cons0);
5096       assert(consdata != NULL);
5097 
5098       cons0vars = consdata->vars;
5099       ncons0vars = consdata->nvars;
5100 
5101       /* sorting array after indices of variables, negated and active counterparts will stand side by side */
5102       SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5103       /* standard setppc-sorting now lost */
5104       consdata->sorted = FALSE;
5105 
5106       /* clique array should be long enough */
5107       assert(maxnvars >= ncons0vars);
5108 
5109       /* clear old entries in overlapping constraint */
5110       BMSclearMemoryArray(countofoverlapping, nusefulconss);
5111 
5112       /* calculate overlapping */
5113       for( v = ncons0vars - 1; v >= 0 ; --v )
5114       {
5115 	 var0 = cons0vars[v];
5116 
5117 	 /* fixed variables later to the count */
5118 	 if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 )
5119 	    continue;
5120 
5121 	 assert(SCIPhashmapExists(vartoindex, (void*) var0));
5122 
5123 	 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0);
5124 	 for( v1 = varnconss[varindex] - 1; v1 >= 0 ; --v1 )
5125 	    ++(countofoverlapping[varconsidxs[varindex][v1]]);
5126       }
5127 
5128       oldnchgcoefs = *nchgcoefs;
5129       cons0fixedzeros = consdata->nfixedzeros;
5130 
5131       chgcons0 = FALSE;
5132 
5133       /* check for overlapping constraint before starting lifting */
5134       SCIP_CALL( checkForOverlapping(scip, cons0, c, c, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex,
5135 	    varnconss, maxnvarconsidx, varconsidxs, countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0,
5136 	    undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations,
5137 	    nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) );
5138 
5139       if( *cutoff )
5140 	 break;
5141 
5142       /* we can't handle aggregated variables later on so we should have saved them for later */
5143       assert(*naggrvars == oldnaggrvars);
5144 
5145       /* if cons0 changed, we need to reorder the variables  */
5146       if( chgcons0 && *nchgcoefs > oldnchgcoefs )
5147       {
5148 	 consdata = SCIPconsGetData(cons0);
5149 	 assert(consdata != NULL);
5150 
5151 	 cons0vars = consdata->vars;
5152 	 ncons0vars = consdata->nvars;
5153 
5154 	 /* sorting array after indices of variables, negated and active counterparts will stand side by side */
5155 	 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5156 	 /* standard setppc-sorting now lost */
5157 	 consdata->sorted = FALSE;
5158       }
5159 
5160       /* check cons0 again for redundancy/fixings, because due to fixings in all other constraints it might happen that cons0 is redundant now */
5161       if( consdata->nfixedones > 0 || consdata->nfixedzeros > cons0fixedzeros )
5162       {
5163 	 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
5164 	  * possible
5165 	  */
5166 	 SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
5167 
5168 	 if( *cutoff )
5169 	    break;
5170 
5171 	 /* we can't handle aggregated variables later on so we should have saved them for later */
5172 	 assert(*naggrvars == oldnaggrvars);
5173 
5174 	 if( !SCIPconsIsActive(cons0) )
5175 	    continue;
5176       }
5177 
5178       nadded = 0;
5179 
5180       /* iterate over the cliques variables and all possible new clique variables at the "same" time, determine starting
5181        * index
5182        *
5183        * @note: it might be better to start the first round with our computed v1, but maybe it's better to switch to
5184        *        trying to add all variables the second time for set packing constraints
5185        */
5186 
5187       /* we try to add all variables to the partitioning constraints, to try to fix as much as possible */
5188       if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
5189          v1 = nusefulvars - 1;
5190       else
5191       {
5192 	 /* if we already ran a presolving round we want to try to add new variables */
5193 	 if( conshdlrdata->nclqpresolve > 0 )
5194 	    v1 = nusefulvars - 1;
5195 	 else
5196 	 {
5197 	    /* find start position of variable which we will try to add to our constraint, so we will get better clique constraints */
5198 	    (void) SCIPsortedvecFindDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, (void*)cons0vars[ncons0vars - 1], nusefulvars, &v1);
5199 	    assert(v1 >= 0 && v1 < nusefulvars);
5200 	    /* if constraint is not merged and we found a variable which is negated the same as it's neighbour we have to
5201 	     * increase v1 to make sure that we don't loose this important variable */
5202 	    if( v1 + 1 < nusefulvars && ((SCIPvarIsNegated(usefulvars[v1 + 1]) && SCIPvarGetNegatedVar(usefulvars[v1 + 1]) == usefulvars[v1]) || (SCIPvarIsNegated(usefulvars[v1]) && SCIPvarGetNegatedVar(usefulvars[v1]) == usefulvars[v1 + 1])) )
5203 	       ++v1;
5204 	 }
5205       }
5206 
5207       assert(maxnvars >= ncons0vars);
5208       /* initialize the cliquevalues array */
5209       for( v = ncons0vars - 1; v >= 0; --v )
5210       {
5211          if( SCIPvarGetLbLocal(cons0vars[v]) < 0.5 && SCIPvarGetUbLocal(cons0vars[v]) > 0.5 )
5212          {
5213             /* variable has to be either active or a negated variable of an active one */
5214             assert(SCIPvarIsActive(cons0vars[v]) || (SCIPvarGetStatus(cons0vars[v]) == SCIP_VARSTATUS_NEGATED &&
5215                   SCIPvarIsActive(SCIPvarGetNegationVar(cons0vars[v]))));
5216             cliquevalues[v] = SCIPvarIsActive(cons0vars[v]) ? TRUE : FALSE;
5217          }
5218       }
5219 
5220       chgcons0 = FALSE;
5221 
5222       /* try to lift variables to cons0 */
5223       SCIP_CALL( liftCliqueVariables(scip, cons0, c, usefulvars, &nusefulvars, v1, &cliquevalues, vartoindex, varnconss,
5224             maxnvarconsidx, varconsidxs, &maxnvars, &nadded, &chgcons0, nfixedvars, ndelconss, cutoff) );
5225 
5226       if( *cutoff )
5227 	 break;
5228 
5229       if( !SCIPconsIsActive(cons0) )
5230 	 continue;
5231 
5232       /* check for redundant constraints due to changing cons0 */
5233       if( chgcons0 )
5234       {
5235          int i;
5236 
5237          *firstchange = MIN(*firstchange, c);
5238          *firstclique = MIN(*firstclique, c);
5239          *lastclique = MAX(*lastclique, c);
5240 
5241 	 /* variables array has changed due to lifting variables, so get new values */
5242 	 assert(consdata == SCIPconsGetData(cons0));
5243 	 cons0vars = consdata->vars;
5244 	 ncons0vars = consdata->nvars;
5245 
5246 	 /* resorting array, because we added new variables, in order of indices of variables, negated
5247 	  * and active counterparts would stand side by side
5248 	  */
5249 	 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5250 	 /* standard setppc-sorting now lost */
5251 	 consdata->sorted = FALSE;
5252 
5253 	 /* clear old entries in overlapping constraint */
5254          BMSclearMemoryArray(countofoverlapping, nusefulconss);
5255 
5256          for( v = ncons0vars - 1; v >= 0 ; --v )
5257          {
5258             var0 = cons0vars[v];
5259 
5260             /* fixed variables later to the count */
5261             if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 )
5262                continue;
5263 
5264             assert(SCIPhashmapExists(vartoindex, (void*) var0));
5265 
5266             varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0);
5267             for( i = varnconss[varindex] - 1; i >= 0 ; --i )
5268                ++(countofoverlapping[varconsidxs[varindex][i]]);
5269          }
5270 
5271 	 chgcons0 = FALSE;
5272 
5273 	 /* check for overlapping constraint after lifting, in the first round we will only check up front */
5274 	 SCIP_CALL( checkForOverlapping(scip, cons0, c, (conshdlrdata->nclqpresolve > 0) ? nusefulconss : c,
5275 	       usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs,
5276 	       countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0,
5277 	       undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations,
5278 	       nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) );
5279 
5280 	 if( *cutoff )
5281 	    break;
5282 
5283 	 /* we can't handle aggregated variables later on so we should have saved them for later */
5284 	 assert(*naggrvars == oldnaggrvars);
5285       }
5286    }
5287 
5288  TERMINATE:
5289    SCIPfreeBufferArrayNull(scip, &countofoverlapping);
5290    SCIPfreeBufferArrayNull(scip, &cliquevalues);
5291 
5292    /* free temporary memory for constraints, variables and the mapping between them in reverse order as they were
5293     * allocated
5294     */
5295    for( c = nusefulvars; c > 0; --c )
5296    {
5297       if( varconsidxs[c] != NULL )
5298       {
5299          SCIPfreeBufferArrayNull(scip, &(varconsidxs[c]));
5300       }
5301    }
5302 
5303    SCIPfreeBufferArray(scip, &varconsidxs);
5304    SCIPfreeBufferArray(scip, &maxnvarconsidx);
5305    SCIPfreeBufferArray(scip, &varnconss);
5306    SCIPfreeBufferArray(scip, &usefulvars);
5307    SCIPfreeBufferArray(scip, &usefulconss);
5308 
5309    /* perform all collected aggregations */
5310    if( !*cutoff && naggregations > 0 && !SCIPdoNotAggr(scip) )
5311    {
5312       SCIP_CALL( performAggregations(scip, conshdlrdata, undoneaggrvars, undoneaggrtypes, naggregations, naggrvars, cutoff) );
5313    }
5314 
5315    /* free temporary memory for the aggregation storage */
5316    SCIPfreeBufferArray(scip, &undoneaggrtypes);
5317    SCIPfreeBufferArray(scip, &undoneaggrvars);
5318 
5319    /* free hashmap */
5320    SCIPhashmapFree(&vartoindex);
5321 
5322    if( *ndelconss < 0 )
5323       *ndelconss = 0;
5324 
5325    return SCIP_OKAY;
5326 }
5327 
5328 
5329 /** add cliques to SCIP */
5330 static
addCliques(SCIP * scip,SCIP_CONS ** conss,int nconss,int firstclique,int lastclique,int * naddconss,int * ndelconss,int * nchgbds,SCIP_Bool * cutoff)5331 SCIP_RETCODE addCliques(
5332    SCIP*                 scip,               /**< SCIP data structure */
5333    SCIP_CONS**           conss,              /**< constraint set */
5334    int                   nconss,             /**< number of constraints in constraint set */
5335    int                   firstclique,        /**< first constraint to start to add cliques */
5336    int                   lastclique,         /**< last constraint to start to add cliques */
5337    int*                  naddconss,          /**< pointer to count number of added constraints */
5338    int*                  ndelconss,          /**< pointer to count number of deleted constraints */
5339    int*                  nchgbds,            /**< pointer to count number of changed bounds */
5340    SCIP_Bool*            cutoff              /**< pointer to store if the problem is infeasible due to a fixing */
5341    )
5342 {
5343    SCIP_CONS* cons;
5344    SCIP_CONSDATA* consdata;
5345    SCIP_Bool infeasible;
5346    int nlocalbdchgs;
5347    int c;
5348 
5349    assert(scip != NULL);
5350    assert(firstclique >= 0);
5351    assert(lastclique <= nconss);
5352    assert(conss != NULL || ((nconss == 0) && (lastclique == 0)));
5353 
5354    /* add clique and implication information */
5355    for( c = firstclique; c < lastclique; ++c )
5356    {
5357       cons = conss[c]; /*lint !e613*/
5358       assert(cons != NULL);
5359 
5360       /* ignore deleted constraints */
5361       if( !SCIPconsIsActive(cons) )
5362          continue;
5363 
5364       nlocalbdchgs = 0;
5365       SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, &nlocalbdchgs, cutoff) );
5366       *nchgbds += nlocalbdchgs;
5367 
5368       if( *cutoff )
5369          return SCIP_OKAY;
5370 
5371       consdata = SCIPconsGetData(cons);
5372       assert(consdata != NULL);
5373 
5374       if( SCIPconsIsDeleted(cons) )
5375          continue;
5376 
5377       if( !consdata->cliqueadded && consdata->nvars >= 2 )
5378       {
5379          /* add a set partitioning / packing constraint as clique */
5380          if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5381          {
5382             SCIP_CALL( SCIPaddClique(scip, consdata->vars, NULL, consdata->nvars,
5383                   ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING), &infeasible, &nlocalbdchgs) );
5384             *nchgbds += nlocalbdchgs;
5385 
5386             if( infeasible )
5387             {
5388                *cutoff = TRUE;
5389                return SCIP_OKAY;
5390             }
5391          }
5392          else if( consdata->nvars == 2 && !SCIPconsIsModifiable(cons) )
5393          {
5394             /* a two-variable set covering constraint x + y >= 1 yields the implication x == 0 -> y == 1 */
5395             SCIP_CALL( SCIPaddVarImplication(scip, consdata->vars[0], FALSE, consdata->vars[1],
5396                   SCIP_BOUNDTYPE_LOWER, 1.0, &infeasible, &nlocalbdchgs) );
5397             *nchgbds += nlocalbdchgs;
5398 
5399             if( infeasible )
5400             {
5401                *cutoff = TRUE;
5402                return SCIP_OKAY;
5403             }
5404          }
5405          consdata->cliqueadded = TRUE;
5406       }
5407    }
5408 
5409    return SCIP_OKAY;
5410 }
5411 
5412 /** perform multi-aggregation on variables resulting from a set-partitioning/-packing constraint */
5413 static
multiAggregateBinvar(SCIP * scip,SCIP_Bool linearconshdlrexist,SCIP_VAR ** vars,int nvars,int pos,SCIP_Bool * infeasible,SCIP_Bool * aggregated)5414 SCIP_RETCODE multiAggregateBinvar(
5415    SCIP*                 scip,               /**< SCIP data structure */
5416    SCIP_Bool             linearconshdlrexist,/**< does the linear constraint handler exist, necessary for multi-aggregations */
5417    SCIP_VAR**            vars,               /**< all variables including the variable to which will be multi-aggregated */
5418    int                   nvars,              /**< number of all variables */
5419    int                   pos,                /**< position of variable for multi-aggregation */
5420    SCIP_Bool*            infeasible,         /**< pointer to store infeasibility status of aggregation */
5421    SCIP_Bool*            aggregated          /**< pointer to store aggregation status */
5422    )
5423 {
5424    SCIP_VAR** tmpvars;
5425    SCIP_Real* scalars;
5426    int v;
5427 
5428    assert(scip != NULL);
5429    assert(vars != NULL);
5430    assert(nvars > 1);
5431    assert(0 <= pos && pos < nvars);
5432    assert(infeasible != NULL);
5433    assert(aggregated != NULL);
5434 
5435    if( nvars == 2 )
5436    {
5437       SCIP_Bool redundant;
5438 
5439       SCIPdebugMsg(scip, "aggregating %s = 1 - %s\n", SCIPvarGetName(vars[pos]), SCIPvarGetName(vars[nvars - pos - 1]));
5440 
5441       /* perform aggregation on variables resulting from a set-packing constraint */
5442       SCIP_CALL( SCIPaggregateVars(scip, vars[pos], vars[nvars - pos - 1], 1.0, 1.0, 1.0, infeasible, &redundant, aggregated) );
5443       assert(*infeasible || *aggregated);
5444 
5445       return SCIP_OKAY;
5446    }
5447 
5448    if( !linearconshdlrexist )
5449    {
5450       *infeasible = FALSE;
5451       return SCIP_OKAY;
5452    }
5453 
5454    /* if the last variable will be multi-aggregated, we do not need to copy the variables */
5455    if( pos == nvars - 1 )
5456       tmpvars = vars;
5457    else
5458    {
5459       /* copy variables for aggregation */
5460       SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
5461       tmpvars[pos] = tmpvars[nvars - 1];
5462    }
5463 
5464    SCIP_CALL( SCIPallocBufferArray(scip, &scalars, nvars - 1) );
5465    /* initialize scalars */
5466    for( v = nvars - 2; v >= 0; --v )
5467       scalars[v] = -1.0;
5468 
5469    SCIPdebugMsg(scip, "multi-aggregating binary variable <%s> (locks: [%d,%d]; to %d variables)\n",
5470       SCIPvarGetName(vars[pos]), SCIPvarGetNLocksDownType(vars[pos], SCIP_LOCKTYPE_MODEL),
5471       SCIPvarGetNLocksUpType(vars[pos], SCIP_LOCKTYPE_MODEL), nvars - 1);
5472 
5473    /* perform multi-aggregation */
5474    SCIP_CALL( SCIPmultiaggregateVar(scip, vars[pos], nvars - 1, tmpvars, scalars, 1.0, infeasible, aggregated) );
5475    assert(!(*infeasible));
5476 
5477    SCIPfreeBufferArray(scip, &scalars);
5478 
5479    if( pos < nvars - 1 )
5480    {
5481       assert(tmpvars != vars);
5482       SCIPfreeBufferArray(scip, &tmpvars);
5483    }
5484 
5485    return SCIP_OKAY;
5486 }
5487 
5488 /** determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and negated)
5489  *  in any combination of set-partitioning and set-packing constraints
5490  *
5491  *  we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint or
5492  *  even delete it
5493  *
5494  *  1. c1: x + y + z = 1,  uplocks(x) = 1, downlocks(x) = 1               =>  x = 1 - y - z and change c1 to y + z <= 1
5495  *
5496  *  2. c2: x + y + z <= 1,  uplocks(x) = 1, downlocks(x) = 0, obj(x) < 0  =>  x = 1 - y - z and change c2 to y + z <= 1
5497  *
5498  *  3. d1: x + y + z <= 1 and d2: ~x + u + v <= 1, uplocks(x) = 1, downlocks(x) = 1
5499  *    a)  obj(x) <= 0                                                     =>  x = 1 - y - z and delete d1
5500  *    b)  obj(x) > 0                                                      => ~x = 1 - u - v and delete d2
5501  *
5502  *  4. e1: x + y + z == 1 and e2: ~x + u + v (<= or ==) 1, uplocks(x) = (1 or 2), downlocks(x) = 2
5503  *                                                                        =>  x = 1 - y - z and delete e1
5504  *
5505  *  we can also aggregate a variable in a set-packing constraint with only two variables when the uplocks are equal to
5506  *  one and then delete this constraint
5507  *
5508  *  5. f1: x + y <= 1,  uplocks(x) = 1, obj(x) <= 0                       =>  x = 1 - y and delete f1
5509  *
5510  *  @todo might want to multi-aggregate variables even with more locks, when the fill in is still smaller or equal to
5511  *        the old number of non-zeros, e.g.
5512  *
5513  *        x + y + z = 1
5514  *        ~x + u + v <=/= 1
5515  *        ~x + w <= 1
5516  */
5517 static
removeDoubleAndSingletonsAndPerformDualpresolve(SCIP * scip,SCIP_CONS ** conss,int nconss,SCIP_Bool dualpresolvingenabled,SCIP_Bool linearconshdlrexist,int * nfixedvars,int * naggrvars,int * ndelconss,int * nchgcoefs,int * nchgsides,SCIP_Bool * cutoff)5518 SCIP_RETCODE removeDoubleAndSingletonsAndPerformDualpresolve(
5519    SCIP*                 scip,               /**< SCIP data structure */
5520    SCIP_CONS**           conss,              /**< constraint set */
5521    int                   nconss,             /**< number of constraints in constraint set */
5522    SCIP_Bool             dualpresolvingenabled,/**< is dual presolving enabled */
5523    SCIP_Bool             linearconshdlrexist,/**< does the linear constraint handler exist, necessary for
5524                                               *   multi-aggregations
5525                                               */
5526    int*                  nfixedvars,         /**< pointer to count number of deleted variables */
5527    int*                  naggrvars,          /**< pointer to count number of aggregated variables */
5528    int*                  ndelconss,          /**< pointer to count number of deleted constraints */
5529    int*                  nchgcoefs,          /**< pointer to count number of changed coefficients */
5530    int*                  nchgsides,          /**< pointer to count number of changed left hand sides */
5531    SCIP_Bool*            cutoff              /**< pointer to store if a cut off was detected */
5532    )
5533 {
5534    SCIP_CONS** usefulconss;
5535    SCIP_VAR** binvars;
5536    SCIP_HASHMAP* vartoindex;
5537    SCIP_Bool* chgtype;
5538    int* considxs;
5539    int* posincons;
5540    SCIP_Bool infeasible;
5541    SCIP_Bool aggregated;
5542    SCIP_Bool donotaggr;
5543    SCIP_Bool donotmultaggr;
5544    SCIP_Bool mustcheck;
5545    SCIP_Bool addcut;
5546    int nposvars;
5547    int ndecs;
5548    int nbinvars;
5549    int nposbinvars;
5550    int nuplocks;
5551    int ndownlocks;
5552    int posreplacements;
5553    int nhashmapentries;
5554    int nlocaladdconss;
5555    int v;
5556    int c;
5557 
5558    assert(scip != NULL);
5559    assert(conss != NULL);
5560    assert(nconss > 0);
5561    assert(nfixedvars != NULL);
5562    assert(naggrvars != NULL);
5563    assert(ndelconss != NULL);
5564    assert(nchgcoefs != NULL);
5565    assert(nchgsides != NULL);
5566 
5567    nbinvars = SCIPgetNBinVars(scip);
5568    nposbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5569    assert(nbinvars + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip) == nposbinvars);
5570 
5571    binvars = SCIPgetVars(scip);
5572 
5573    /* determine number for possible multi-aggregations */
5574    nposvars = 0;
5575    for( v = nposbinvars - 1; v >= 0; --v )
5576    {
5577       assert(SCIPvarGetType(binvars[v]) != SCIP_VARTYPE_CONTINUOUS);
5578 
5579       if( v < nbinvars || SCIPvarIsBinary(binvars[v]) )
5580       {
5581          nuplocks = SCIPvarGetNLocksUpType(binvars[v], SCIP_LOCKTYPE_MODEL);
5582          ndownlocks = SCIPvarGetNLocksDownType(binvars[v], SCIP_LOCKTYPE_MODEL);
5583 
5584          if( (nuplocks == 1 && ndownlocks <= 1) || (nuplocks <= 1 && ndownlocks == 1) || (nuplocks <= 2 && ndownlocks <= 2 && SCIPvarGetNegatedVar(binvars[v]) != NULL) )
5585             ++nposvars;
5586       }
5587    }
5588 
5589    SCIPdebugMsg(scip, "found %d binary variables for possible multi-aggregation\n", nposvars);
5590 
5591    if( nposvars == 0 )
5592       return SCIP_OKAY;
5593 
5594    /* a hashmap from var to index when found in a set-partitioning constraint */
5595    SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nposvars) );
5596 
5597    /* get temporary memory */
5598    SCIP_CALL( SCIPallocBufferArray(scip, &chgtype, nconss) );
5599    BMSclearMemoryArray(chgtype, nconss);
5600 
5601    SCIP_CALL( SCIPallocBufferArray(scip, &considxs, nposbinvars) );
5602    SCIP_CALL( SCIPallocBufferArray(scip, &posincons, nposbinvars) );
5603 
5604    SCIP_CALL( SCIPduplicateBufferArray(scip, &usefulconss, conss, nconss) );
5605    /* sort constraints */
5606    SCIPsortPtr((void**)usefulconss, setppcConssSort2, nconss);
5607 
5608    posreplacements = 0;
5609    nhashmapentries = 0;
5610    ndecs = 0;
5611    donotaggr = SCIPdoNotAggr(scip);
5612    donotmultaggr = SCIPdoNotMultaggr(scip);
5613    assert(!donotaggr || !donotmultaggr);
5614 
5615    /* determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and
5616     * negated) in any combination of set-partitioning and set-packing constraints
5617     *
5618     * we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint
5619     * or even delete it
5620     */
5621    for( c = 0; c < nconss; ++c )
5622    {
5623       SCIP_CONS* cons;
5624       SCIP_CONSDATA* consdata;
5625       int oldnfixedvars;
5626       nlocaladdconss = 0;
5627 
5628       cons = usefulconss[c];
5629       assert(cons != NULL);
5630 
5631       if( SCIPconsIsDeleted(cons) )
5632          continue;
5633 
5634       consdata = SCIPconsGetData(cons);
5635       assert(consdata != NULL);
5636 
5637       /* if we cannot find any constraint to perform a useful multi-aggregation, stop */
5638       if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING )
5639          break;
5640 
5641       if( !SCIPconsIsChecked(cons) )
5642          continue;
5643 
5644       if( SCIPconsIsModifiable(cons) )
5645          continue;
5646 
5647       /* update the variables */
5648       SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
5649 
5650       if( *cutoff )
5651          break;
5652 
5653       /* due to resolving multi-aggregations a constraint can become deleted */
5654       if( SCIPconsIsDeleted(cons) )
5655          continue;
5656 
5657       SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) );
5658       assert(!addcut);
5659 
5660       if( *cutoff )
5661          break;
5662 
5663       if( SCIPconsIsDeleted(cons) )
5664          continue;
5665 
5666       oldnfixedvars = *nfixedvars;
5667 
5668       /* merging unmerged constraints */
5669       SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
5670 
5671       if( *cutoff )
5672          break;
5673 
5674       if( SCIPconsIsDeleted(cons) )
5675          continue;
5676 
5677       if( oldnfixedvars < *nfixedvars )
5678       {
5679          /* update the variables */
5680          SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
5681          assert(!SCIPconsIsDeleted(cons));
5682          assert(nlocaladdconss == 0);
5683          assert(!*cutoff);
5684 
5685          if( SCIPconsIsDeleted(cons) )
5686             continue;
5687       }
5688 
5689       /* if the constraint was not merged and consists of a variable with its negation, the constraint is redundant */
5690       if( consdata->nvars < 2 )
5691       {
5692          /* deleting redundant set-packing constraint */
5693          if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5694          {
5695 	    SCIPdebugMsg(scip, "deleting redundant set-packing constraint <%s>\n", SCIPconsGetName(cons));
5696 
5697             SCIP_CALL( SCIPdelCons(scip, cons) );
5698             ++(*ndelconss);
5699 
5700             continue;
5701          }
5702          else
5703          {
5704             SCIP_Bool fixed;
5705 
5706             assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
5707 
5708             if( consdata->nvars == 0 )
5709             {
5710                SCIPdebugMsg(scip, "empty set partition constraint <%s> led to infeasibility\n", SCIPconsGetName(cons));
5711 
5712                *cutoff = TRUE;
5713                break;
5714             }
5715 
5716 	    SCIPdebugMsg(scip, "fixing <%s> to 1 because this variable is the last variable in a set partition constraint <%s>\n", SCIPvarGetName(consdata->vars[0]), SCIPconsGetName(cons));
5717 
5718             SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], 1.0, &infeasible, &fixed) );
5719             assert(!infeasible);
5720 
5721             if( fixed )
5722                ++(*nfixedvars);
5723 
5724             assert(SCIPvarGetLbGlobal(consdata->vars[0]) > 0.5);
5725 
5726 	    SCIPdebugMsg(scip, "deleting redundant set-partition constraint <%s>\n", SCIPconsGetName(cons));
5727 
5728             SCIP_CALL( SCIPdelCons(scip, cons) );
5729             ++(*ndelconss);
5730 
5731             continue;
5732          }
5733       }
5734 
5735       /* perform dualpresolve on set-packing constraints with exactly two variables */
5736       if( !donotaggr && consdata->nvars == 2 && dualpresolvingenabled && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5737       {
5738          SCIP_VAR* var;
5739          SCIP_Real objval;
5740          SCIP_Bool redundant;
5741 
5742          var = consdata->vars[0];
5743          assert(var != NULL);
5744          assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
5745 
5746          SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) );
5747 
5748          nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
5749 
5750          if( nuplocks == 1 && objval <= 0 )
5751          {
5752             SCIPdebugMsg(scip, "dualpresolve, aggregating %s + %s = 1, in set-packing constraint %s\n", SCIPvarGetName(var), SCIPvarGetName(consdata->vars[1]), SCIPconsGetName(cons));
5753 
5754             /* perform aggregation on variables resulting from a set-packing constraint */
5755             SCIP_CALL( SCIPaggregateVars(scip, var, consdata->vars[1], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
5756 
5757             if( infeasible )
5758             {
5759                *cutoff = TRUE;
5760                break;
5761             }
5762 
5763             assert(aggregated);
5764             ++(*naggrvars);
5765 
5766             SCIP_CALL( SCIPdelCons(scip, cons) );
5767             ++(*ndelconss);
5768 
5769             continue;
5770          }
5771          else
5772          {
5773             var = consdata->vars[1];
5774             assert(var != NULL);
5775             assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
5776 
5777             SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) );
5778 
5779             nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
5780 
5781             if( nuplocks == 1 && objval <= 0 )
5782             {
5783                SCIPdebugMsg(scip, "dualpresolve, aggregating %s + %s = 1, in set-packing constraint %s\n", SCIPvarGetName(var), SCIPvarGetName(consdata->vars[0]), SCIPconsGetName(cons));
5784 
5785                /* perform aggregation on variables resulting from a set-packing constraint */
5786                SCIP_CALL( SCIPaggregateVars(scip, var, consdata->vars[0], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
5787 
5788                if( infeasible )
5789                {
5790                   *cutoff = TRUE;
5791                   break;
5792                }
5793                assert(aggregated);
5794                ++(*naggrvars);
5795 
5796                SCIP_CALL( SCIPdelCons(scip, cons) );
5797                ++(*ndelconss);
5798 
5799                continue;
5800             }
5801          }
5802       }
5803       else if( !donotaggr && consdata->nvars == 2 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
5804       {
5805          SCIP_Bool redundant;
5806 
5807          SCIPdebugMsg(scip, "aggregating %s + %s = 1, in set-partition constraint %s\n", SCIPvarGetName(consdata->vars[0]), SCIPvarGetName(consdata->vars[1]), SCIPconsGetName(cons));
5808 
5809          /* perform aggregation on variables resulting from a set-partitioning constraint */
5810          SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
5811 
5812          if( infeasible )
5813          {
5814             *cutoff = TRUE;
5815             break;
5816          }
5817 
5818          assert(aggregated);
5819          ++(*naggrvars);
5820 
5821          SCIP_CALL( SCIPdelCons(scip, cons) );
5822          ++(*ndelconss);
5823 
5824          continue;
5825       }
5826 
5827       /* we already found all possible variables for multi-aggregation */
5828       if( ndecs >= nposvars )
5829          continue;
5830 
5831       /* no multi aggregation is allowed, so we can continue */
5832       if( donotmultaggr )
5833          continue;
5834 
5835       /* if the following condition does not hold, we have an unmerged constraint, and we might need to merge it first */
5836       assert(nposbinvars >= consdata->nvars);
5837 
5838       /* search for possible variables for multi-aggregation */
5839       for( v = consdata->nvars - 1; v >= 0; --v )
5840       {
5841          SCIP_VAR* var;
5842          int deleteconsindex = -1;
5843 
5844          var = consdata->vars[v];
5845          assert(var != NULL);
5846          assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
5847 
5848          aggregated = FALSE;
5849          nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
5850          ndownlocks = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
5851          assert(nuplocks >= 1 && ndownlocks >= 0); /* we are only treating set partitioning and set packing constraints, so every variable in there should have an uplock */
5852 
5853          if( dualpresolvingenabled && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING && nuplocks <= 1 && nuplocks + ndownlocks <= 2 )
5854          {
5855             assert(nuplocks == 1 && ndownlocks <= 1);
5856 
5857             /* we found a redundant variable in a set-partitioning constraint */
5858             if( ndownlocks == 0 )
5859             {
5860                SCIP_Real objval;
5861 
5862                SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) );
5863 
5864                /* if the objective value is >= 0 the fixing is normally done by the dualfix presolver */
5865                if( !SCIPisNegative(scip, objval) )
5866                {
5867                   SCIP_Bool fixed;
5868 
5869                   SCIPdebugMsg(scip, "dual-fixing of variable <%s> to 0.0\n", SCIPvarGetName(var));
5870 
5871                   SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
5872                   assert(!infeasible);
5873                   assert(fixed);
5874 
5875                   ++(*nfixedvars);
5876                }
5877                else
5878                {
5879                   SCIPdebugMsg(scip, "multi-aggregating in set-packing constraint\n");
5880 
5881                   /* perform aggregation on variables resulting from a set-packing constraint */
5882                   SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
5883 
5884                   if( infeasible )
5885                   {
5886                      *cutoff = TRUE;
5887                      break;
5888                   }
5889                }
5890 
5891                ++ndecs;
5892             }
5893             else if( ndownlocks == 1 && SCIPvarGetNegatedVar(var) != NULL )
5894             {
5895                SCIP_CONSDATA* aggrconsdata;
5896                SCIP_VAR* negvar;
5897                SCIP_VAR* activevar;
5898                SCIP_Real objval;
5899                int multaggridx;
5900                int notmultaggridx;
5901                int image;
5902                int consindex;
5903                int varindex;
5904 
5905                assert(!SCIPhashmapExists(vartoindex, (void*) var));
5906 
5907                negvar = SCIPvarGetNegatedVar(var);
5908 
5909                /* if we found a new variable add it to the data */
5910                if( !SCIPhashmapExists(vartoindex, (void*) negvar) )
5911                {
5912                   ++nhashmapentries;
5913                   SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, nhashmapentries) );
5914 
5915                   considxs[nhashmapentries - 1] = c;
5916                   posincons[nhashmapentries - 1] = v;
5917 
5918                   ++posreplacements;
5919                   continue;
5920                }
5921 
5922                assert(SCIPhashmapExists(vartoindex, (void*) negvar));
5923                image = SCIPhashmapGetImageInt(vartoindex, (void*) negvar);
5924                assert(image > 0 && image <= nhashmapentries);
5925 
5926                consindex = considxs[image - 1];
5927                assert(0 <= consindex && consindex < nconss);
5928 
5929                /* if the following assert fails, the constraint was not merged, or something really strange happened */
5930                assert(consindex < c);
5931 
5932                ++ndecs;
5933                --posreplacements;
5934                assert(posreplacements >= 0);
5935 
5936                varindex = posincons[image - 1];
5937                considxs[image - 1] = -1;
5938                posincons[image - 1] = -1;
5939                SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) negvar) );
5940 
5941                /* if two variables in one constraint might be multi-aggregated, it might happen that this constraint was already removed */
5942                if( SCIPconsIsDeleted(usefulconss[consindex]) )
5943                   continue;
5944 
5945                aggrconsdata = SCIPconsGetData(usefulconss[consindex]);
5946                assert(aggrconsdata != NULL);
5947                assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING);
5948                assert(0 <= varindex);
5949 
5950                /* it might be that due to other multi-aggregations the constraint has fewer variables than when we
5951                 * remembered the position, therefore we need to find the variable again
5952                 */
5953                if( varindex >= aggrconsdata->nvars || aggrconsdata->vars[varindex] != negvar )
5954                {
5955                   int v2;
5956 
5957                   /* if the following assert is raised, then the constraint is redundant and we do not need to aggregate
5958                    * anymore and can delete this constraint
5959                    */
5960                   assert(aggrconsdata->nvars >= 2);
5961 
5962                   for( v2 = aggrconsdata->nvars - 1; v2 >= 0; --v2 )
5963                   {
5964                      if( aggrconsdata->vars[v2] == negvar )
5965                         break;
5966                   }
5967                   assert(v2 >= 0);
5968 
5969                   varindex = v2;
5970                }
5971                assert(0 <= varindex && varindex < aggrconsdata->nvars);
5972                assert(aggrconsdata->vars[varindex] == negvar);
5973                assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(negvar) == SCIP_VARSTATUS_NEGATED);
5974 
5975                /* determine active variable and constraint that corresponds to */
5976                if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
5977                {
5978                   activevar = negvar;
5979                   multaggridx = consindex;
5980                   notmultaggridx = c;
5981                }
5982                else
5983                {
5984                   activevar = var;
5985                   multaggridx = c;
5986                   notmultaggridx = consindex;
5987                }
5988                objval = SCIPvarGetObj(activevar);
5989 
5990                SCIPdebugMsg(scip, "multi-aggregating in two set-packing constraint\n");
5991 
5992                if( objval <= 0.0 )
5993                {
5994                   /* perform aggregation on variables resulting from a set-packing constraint */
5995                   if( multaggridx == c )
5996                   {
5997                      SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
5998                   }
5999                   else
6000                   {
6001                      SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) );
6002                   }
6003                   deleteconsindex = multaggridx;
6004                }
6005                else
6006                {
6007                   /* perform aggregation on variables resulting from a set-packing constraint */
6008                   /* coverity[copy_paste_error] */
6009                   if( multaggridx == c )
6010                   {
6011                      SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) );
6012                   }
6013                   else
6014                   {
6015                      SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
6016                   }
6017                   deleteconsindex = notmultaggridx;
6018                }
6019 
6020                if( infeasible )
6021                {
6022                   *cutoff = TRUE;
6023                   break;
6024                }
6025 
6026                assert(deleteconsindex >= 0 && deleteconsindex <= c);
6027             }
6028          }
6029          /* we found a redundant variable in a set-partitioning constraint */
6030          else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && nuplocks == 1 && ndownlocks == 1 )
6031          {
6032             SCIPdebugMsg(scip, "multi-aggregating in set-partitioning constraint\n");
6033 
6034             /* perform aggregation on variables resulting from a set-partitioning constraint */
6035             SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
6036 
6037             if( infeasible )
6038             {
6039                *cutoff = TRUE;
6040                break;
6041             }
6042 
6043             ++ndecs;
6044          }
6045          /* we might have found a redundant variable */
6046          else if( ndownlocks <= 2 && nuplocks <= 2 && SCIPvarGetNegatedVar(var) != NULL )
6047          {
6048             SCIP_CONSDATA* aggrconsdata;
6049             int image;
6050             int consindex;
6051             int varindex;
6052 
6053             /* if we have two times the same variable in a set-partitioning constraint, we cannot aggregate this */
6054             if( SCIPhashmapExists(vartoindex, (void*) var) )
6055             {
6056                image = SCIPhashmapGetImageInt(vartoindex, (void*) var);
6057                assert(image > 0 && image <= nhashmapentries);
6058 
6059                assert(0 <= considxs[image - 1] && considxs[image - 1] < nconss);
6060                assert(SCIPconsIsDeleted(usefulconss[considxs[image - 1]]) || chgtype[considxs[image - 1]] || (0 <= posincons[image - 1] && posincons[image - 1] < SCIPconsGetData(usefulconss[considxs[image - 1]])->nvars));
6061 
6062                considxs[image - 1] = -1;
6063                posincons[image - 1] = -1;
6064 
6065                SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) var) );
6066 
6067                --posreplacements;
6068                assert(posreplacements >= 0);
6069 
6070                continue;
6071             }
6072             else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
6073             {
6074                /* if we found a new variable add it to the data */
6075                if( !SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)) )
6076                {
6077                   assert(!SCIPhashmapExists(vartoindex, (void*) var));
6078 
6079                   ++nhashmapentries;
6080                   SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, nhashmapentries) );
6081 
6082                   considxs[nhashmapentries - 1] = c;
6083                   posincons[nhashmapentries - 1] = v;
6084 
6085                   ++posreplacements;
6086                   continue;
6087                }
6088             }
6089             else
6090             {
6091                assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING);
6092 
6093                /* the negated variable did not occur in a set partitioning constraint (those will be iterated over
6094                 * first), so we cannot aggregate this variable
6095                 */
6096                if( !SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)) )
6097                   continue;
6098             }
6099 
6100             assert(!chgtype[c]);
6101             assert(SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)));
6102             image = SCIPhashmapGetImageInt(vartoindex, (void*) SCIPvarGetNegatedVar(var));
6103             assert(image > 0 && image <= nhashmapentries);
6104 
6105             consindex = considxs[image - 1];
6106             assert(0 <= consindex && consindex < nconss);
6107 
6108             /* if the following assert fails, the constraint was not merged, or something really strange happened */
6109             assert(consindex < c);
6110 
6111             ++ndecs;
6112             --posreplacements;
6113             assert(posreplacements >= 0);
6114 
6115             varindex = posincons[image - 1];
6116             considxs[image - 1] = -1;
6117             posincons[image - 1] = -1;
6118             SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) SCIPvarGetNegatedVar(var)) );
6119 
6120             /* if two variables in one constraint might be multi-aggregated, it might happen that this constraint was
6121              * already removed
6122              */
6123             if( SCIPconsIsDeleted(usefulconss[consindex]) )
6124                continue;
6125 
6126             aggrconsdata = SCIPconsGetData(usefulconss[consindex]);
6127             assert(aggrconsdata != NULL);
6128 
6129             /* must not multi-aggregate variables that are locked more then twice by all setppc constraints */
6130             if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING &&
6131                (SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING )
6132             {
6133                assert(!dualpresolvingenabled || nuplocks + ndownlocks > 2);
6134                continue;
6135             }
6136 
6137             assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ||
6138                (SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
6139 
6140             /* we already removed a variable before, so our positioning information might be wrong, so we need to walk
6141              * over all variables again
6142              */
6143             if( chgtype[consindex] )
6144             {
6145 #ifndef NDEBUG
6146                int v2;
6147 
6148                assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING);
6149 
6150                /* negated variables needs to be still in the upgraded set-packing constraint */
6151                for( v2 = aggrconsdata->nvars - 1; v2 >= 0; --v2 )
6152                {
6153                   if( aggrconsdata->vars[v2] == SCIPvarGetNegatedVar(var) )
6154                      break;
6155                }
6156                assert(v2 >= 0);
6157 #endif
6158                assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
6159 
6160                SCIPdebugMsg(scip, "multi-aggregating in one set-partitioning or one set-packing constraint\n");
6161 
6162                /* perform aggregation on variables resulting from a set-partitioning constraint */
6163                SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
6164 
6165                if( infeasible )
6166                {
6167                   *cutoff = TRUE;
6168                   break;
6169                }
6170                assert(deleteconsindex == -1);
6171             }
6172             else
6173             {
6174                /* @note it might have happened that we have a variable at hand which exists actually in a set-packing
6175                 *       constraint and due to some other aggregation we increased the number of locks and reached this
6176                 *       part of the code, where we would expect only set-partitioning constraints in general, so in
6177                 *       such a strange case we cannot aggregate anything
6178                 */
6179                if( (SCIP_SETPPCTYPE)aggrconsdata->setppctype != SCIP_SETPPCTYPE_PARTITIONING )
6180                   continue;
6181 
6182                assert(0 <= varindex && varindex < aggrconsdata->nvars);
6183                assert(aggrconsdata->vars[varindex] == SCIPvarGetNegatedVar(var));
6184                assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
6185 
6186                SCIPdebugMsg(scip, "multi-aggregating in two set-partitioning or one set-partitioning and -packing constraint\n");
6187 
6188                /* perform aggregation on variables resulting from a set-partitioning constraint */
6189                SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) );
6190 
6191                if( infeasible )
6192                {
6193                   *cutoff = TRUE;
6194                   break;
6195                }
6196 
6197                /* change pointer for deletion */
6198                cons = usefulconss[consindex];
6199                assert(deleteconsindex == -1);
6200             }
6201          }
6202 
6203          if( aggregated )
6204          {
6205             assert(nuplocks >= 1 && ndownlocks >= 0); /* repeated from above */
6206             ++(*naggrvars);
6207 
6208             if( nuplocks == 1 && ndownlocks == 0 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
6209             {
6210                assert(deleteconsindex < 0);
6211 
6212                SCIP_CALL( delCoefPos(scip, cons, v) );
6213                ++(*nchgcoefs);
6214             }
6215             else if( nuplocks == 1 && ndownlocks == 1 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
6216             {
6217                assert(deleteconsindex < 0);
6218 
6219                SCIP_CALL( delCoefPos(scip, cons, v) );
6220                ++(*nchgcoefs);
6221 
6222                SCIPdebugMsg(scip, "changing constraint <%s> from set-partitioning to set-packing, due to multi-aggregation\n", SCIPconsGetName(cons));
6223 
6224                chgtype[c] = TRUE;
6225 
6226                SCIP_CALL( setSetppcType(scip, cons, SCIP_SETPPCTYPE_PACKING) );
6227                ++(*nchgsides);
6228             }
6229             else
6230             {
6231                if( deleteconsindex >= 0 )
6232                {
6233                   SCIPdebugMsg(scip, "1: deleting redundant constraint <%s>, due to multi-aggregation\n", SCIPconsGetName(usefulconss[deleteconsindex]));
6234                   SCIPdebugPrintCons(scip, usefulconss[deleteconsindex], NULL);
6235 
6236                   assert(!SCIPconsIsDeleted(usefulconss[deleteconsindex]));
6237                   SCIP_CALL( SCIPdelCons(scip, usefulconss[deleteconsindex]) );
6238                }
6239                else
6240                {
6241                   SCIPdebugMsg(scip, "2: deleting redundant constraint <%s>, due to multi-aggregation\n", SCIPconsGetName(cons));
6242                   SCIPdebugPrintCons(scip, cons, NULL);
6243 
6244                   assert(!SCIPconsIsDeleted(cons));
6245                   SCIP_CALL( SCIPdelCons(scip, cons) );
6246                }
6247                ++(*ndelconss);
6248             }
6249 
6250             break;
6251          }
6252       }
6253    }
6254 
6255    /* free temporary memory */
6256    SCIPfreeBufferArray(scip, &usefulconss);
6257    SCIPfreeBufferArray(scip, &posincons);
6258    SCIPfreeBufferArray(scip, &considxs);
6259    SCIPfreeBufferArray(scip, &chgtype);
6260 
6261    /* free hashmap */
6262    SCIPhashmapFree(&vartoindex);
6263 
6264    return SCIP_OKAY;
6265 }
6266 
6267 
6268 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
6269  *  accordingly; in contrast to removeRedundantConstraints(), it uses a hash table
6270  */
6271 static
detectRedundantConstraints(SCIP * scip,BMS_BLKMEM * blkmem,SCIP_CONS ** conss,int nconss,int * firstchange,int * ndelconss,int * nchgsides)6272 SCIP_RETCODE detectRedundantConstraints(
6273    SCIP*                 scip,               /**< SCIP data structure */
6274    BMS_BLKMEM*           blkmem,             /**< block memory */
6275    SCIP_CONS**           conss,              /**< constraint set */
6276    int                   nconss,             /**< number of constraints in constraint set */
6277    int*                  firstchange,        /**< pointer to store first changed constraint */
6278    int*                  ndelconss,          /**< pointer to count number of deleted constraints */
6279    int*                  nchgsides           /**< pointer to count number of changed left/right hand sides */
6280    )
6281 {
6282    SCIP_HASHTABLE* hashtable;
6283    int hashtablesize;
6284    int c;
6285 
6286    assert(scip != NULL);
6287    assert(blkmem != NULL);
6288    assert(conss != NULL || nconss == 0);
6289    assert(firstchange != NULL);
6290    assert(ndelconss != NULL);
6291    assert(nchgsides != NULL);
6292 
6293    if( nconss == 0 )
6294       return SCIP_OKAY;
6295 
6296    assert(conss != NULL);
6297 
6298    /* create a hash table for the constraint set */
6299    hashtablesize = nconss;
6300    hashtablesize = MAX(hashtablesize, HASHSIZE_SETPPCCONS);
6301    SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
6302          hashGetKeySetppccons, hashKeyEqSetppccons, hashKeyValSetppccons, (void*) scip) );
6303 
6304    /* check all constraints in the given set for redundancy */
6305    for( c = 0; c < nconss; ++c )
6306    {
6307       SCIP_CONS* cons0;
6308       SCIP_CONS* cons1;
6309 
6310       cons0 = conss[c];
6311 
6312       if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
6313          continue;
6314 
6315       /* get constraint from current hash table with same variables as cons0 and with coefficients either equal or negated
6316        * to the ones of cons0 */
6317       cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
6318 
6319       if( cons1 != NULL )
6320       {
6321          SCIP_CONSDATA* consdata0;
6322          SCIP_CONSDATA* consdata1;
6323 
6324          assert(SCIPconsIsActive(cons1));
6325          assert(!SCIPconsIsModifiable(cons1));
6326 
6327          /* constraint found: create a new constraint with same coefficients and best left and right hand side;
6328           * delete old constraints afterwards
6329           */
6330          consdata0 = SCIPconsGetData(cons0);
6331          consdata1 = SCIPconsGetData(cons1);
6332 
6333          assert(consdata0 != NULL && consdata1 != NULL);
6334          assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars);
6335 
6336          assert(consdata0->sorted && consdata1->sorted);
6337          assert(consdata0->vars[0] == consdata1->vars[0]);
6338 
6339          SCIPdebugMsg(scip, "setppc constraints <%s> and <%s> have identical variable sets\n",
6340             SCIPconsGetName(cons0), SCIPconsGetName(cons1));
6341          SCIPdebugPrintCons(scip, cons0, NULL);
6342          SCIPdebugPrintCons(scip, cons1, NULL);
6343 
6344          /* if necessary change type of setppc constraint */
6345          if( consdata1->setppctype != SCIP_SETPPCTYPE_PARTITIONING && consdata0->setppctype != consdata1->setppctype ) /*lint !e641*/
6346          {
6347             /* change the type of cons0 */
6348             SCIP_CALL( setSetppcType(scip, cons1, SCIP_SETPPCTYPE_PARTITIONING) );
6349             (*nchgsides)++;
6350          }
6351 
6352          /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
6353          /* coverity[swapped_arguments] */
6354          SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
6355 
6356          /* delete cons0 */
6357          SCIP_CALL( SCIPdelCons(scip, cons0) );
6358          (*ndelconss)++;
6359 
6360          /* update the first changed constraint to begin the next aggregation round with */
6361          if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange )
6362             *firstchange = SCIPconsGetPos(cons1);
6363 
6364          assert(SCIPconsIsActive(cons1));
6365       }
6366       else
6367       {
6368          /* no such constraint in current hash table: insert cons0 into hash table */
6369          SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
6370       }
6371    }
6372 
6373    /* free hash table */
6374    SCIPhashtableFree(&hashtable);
6375 
6376    return SCIP_OKAY;
6377 }
6378 
6379 /** removes the redundant second constraint and updates the flags of the first one */
6380 static
removeRedundantCons(SCIP * scip,SCIP_CONS * cons0,SCIP_CONS * cons1,int * ndelconss)6381 SCIP_RETCODE removeRedundantCons(
6382    SCIP*                 scip,               /**< SCIP data structure */
6383    SCIP_CONS*            cons0,              /**< constraint that should stay */
6384    SCIP_CONS*            cons1,              /**< constraint that should be deleted */
6385    int*                  ndelconss           /**< pointer to count number of deleted constraints */
6386    )
6387 {
6388    assert(ndelconss != NULL);
6389 
6390    SCIPdebugMsg(scip, " -> removing setppc constraint <%s> which is redundant to <%s>\n",
6391       SCIPconsGetName(cons1), SCIPconsGetName(cons0));
6392    SCIPdebugPrintCons(scip, cons0, NULL);
6393    SCIPdebugPrintCons(scip, cons1, NULL);
6394 
6395    /* update flags of cons0 */
6396    SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
6397 
6398    /* delete cons1 */
6399    SCIP_CALL( SCIPdelCons(scip, cons1) );
6400    (*ndelconss)++;
6401 
6402    return SCIP_OKAY;
6403 }
6404 
6405 /** for cons0 contained in cons1, fixes variables of cons1 that are not in cons0 to zero */
6406 static
fixAdditionalVars(SCIP * scip,SCIP_CONS * cons0,SCIP_CONS * cons1,SCIP_Bool * cutoff,int * nfixedvars)6407 SCIP_RETCODE fixAdditionalVars(
6408    SCIP*                 scip,               /**< SCIP data structure */
6409    SCIP_CONS*            cons0,              /**< constraint that is contained in the other */
6410    SCIP_CONS*            cons1,              /**< constraint that is a superset of the other */
6411    SCIP_Bool*            cutoff,             /**< pointer to store whether a cutoff was found */
6412    int*                  nfixedvars          /**< pointer to count number of fixed variables */
6413    )
6414 {
6415    SCIP_CONSDATA* consdata0;
6416    SCIP_CONSDATA* consdata1;
6417    int v0;
6418    int v1;
6419 
6420    assert(cutoff != NULL);
6421    assert(nfixedvars != NULL);
6422 
6423    *cutoff = FALSE;
6424 
6425    /* get constraint data */
6426    consdata0 = SCIPconsGetData(cons0);
6427    consdata1 = SCIPconsGetData(cons1);
6428    assert(consdata0 != NULL);
6429    assert(consdata1 != NULL);
6430    assert(consdata0->nvars < consdata1->nvars);
6431    assert(consdata0->sorted);
6432    assert(consdata1->sorted);
6433 
6434    /* fix variables in the range of cons0 */
6435    for( v0 = 0, v1 = 0; v0 < consdata0->nvars && !(*cutoff); ++v0, ++v1 )
6436    {
6437       int index0;
6438 
6439       assert(v1 < consdata1->nvars);
6440       index0 = SCIPvarGetIndex(consdata0->vars[v0]);
6441       for( ; SCIPvarGetIndex(consdata1->vars[v1]) < index0 && !(*cutoff); ++v1 ) /*lint !e445*/
6442       {
6443          SCIP_Bool fixed;
6444 
6445          /* fix variable to zero */
6446          SCIP_CALL( SCIPfixVar(scip, consdata1->vars[v1], 0.0, cutoff, &fixed) );
6447          if( fixed )
6448          {
6449             SCIPdebugMsg(scip, " -> fixed <%s> == 0\n", SCIPvarGetName(consdata1->vars[v1]));
6450             (*nfixedvars)++;
6451          }
6452          assert(v1 < consdata1->nvars-1);
6453       }
6454       assert(SCIPvarGetIndex(consdata1->vars[v1]) == index0 || *cutoff);
6455    }
6456 
6457    /* fix remaining variables of cons1 */
6458    for( ; v1 < consdata1->nvars && !(*cutoff); ++v1 )
6459    {
6460       SCIP_Bool fixed;
6461 
6462       assert(consdata0->nvars == 0
6463          || SCIPvarGetIndex(consdata1->vars[v1]) > SCIPvarGetIndex(consdata0->vars[consdata0->nvars-1]));
6464 
6465       /* fix variable to zero */
6466       SCIP_CALL( SCIPfixVar(scip, consdata1->vars[v1], 0.0, cutoff, &fixed) );
6467       if( fixed )
6468       {
6469          SCIPdebugMsg(scip, " -> fixed <%s> == 0\n", SCIPvarGetName(consdata1->vars[v1]));
6470          (*nfixedvars)++;
6471       }
6472    }
6473 
6474    return SCIP_OKAY;
6475 }
6476 
6477 /** applies reductions for cons0 being contained in cons1 */
6478 static
processContainedCons(SCIP * scip,SCIP_CONS * cons0,SCIP_CONS * cons1,SCIP_Bool * cutoff,int * nfixedvars,int * ndelconss,int * nchgsides)6479 SCIP_RETCODE processContainedCons(
6480    SCIP*                 scip,               /**< SCIP data structure */
6481    SCIP_CONS*            cons0,              /**< constraint that is contained in the other */
6482    SCIP_CONS*            cons1,              /**< constraint that is a superset of the other */
6483    SCIP_Bool*            cutoff,             /**< pointer to store whether a cutoff was found */
6484    int*                  nfixedvars,         /**< pointer to count number of fixed variables */
6485    int*                  ndelconss,          /**< pointer to count number of deleted constraints */
6486    int*                  nchgsides           /**< pointer to count number of changed left/right hand sides */
6487    )
6488 {
6489    SCIP_CONSDATA* consdata0;
6490    SCIP_CONSDATA* consdata1;
6491 
6492    assert(cutoff != NULL);
6493    assert(nfixedvars != NULL);
6494    assert(ndelconss != NULL);
6495    assert(nchgsides != NULL);
6496 
6497    *cutoff = FALSE;
6498 
6499    /* get constraint data */
6500    consdata0 = SCIPconsGetData(cons0);
6501    consdata1 = SCIPconsGetData(cons1);
6502    assert(consdata0 != NULL);
6503    assert(consdata1 != NULL);
6504    assert(consdata0->nvars < consdata1->nvars);
6505    assert(consdata0->sorted);
6506    assert(consdata1->sorted);
6507 
6508    switch( consdata0->setppctype )
6509    {
6510    case SCIP_SETPPCTYPE_PARTITIONING:
6511       switch( consdata1->setppctype )
6512       {
6513       case SCIP_SETPPCTYPE_PARTITIONING:
6514       case SCIP_SETPPCTYPE_PACKING:
6515          /* cons0: partitioning, cons1: partitioning or packing
6516           * -> fix additional variables in cons1 to zero, remove cons1
6517           */
6518          SCIP_CALL( fixAdditionalVars(scip, cons0, cons1, cutoff, nfixedvars) );
6519          SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6520          break;
6521 
6522       case SCIP_SETPPCTYPE_COVERING:
6523          /* cons0: partitioning, cons1: covering
6524           * -> remove cons1
6525           */
6526          SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6527          break;
6528 
6529       default:
6530          SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1));
6531          return SCIP_INVALIDDATA;
6532       }
6533       break;
6534 
6535    case SCIP_SETPPCTYPE_PACKING:
6536       switch( consdata1->setppctype )
6537       {
6538       case SCIP_SETPPCTYPE_PARTITIONING:
6539       case SCIP_SETPPCTYPE_PACKING:
6540          /* cons0: packing, cons1: partitioning or packing
6541           * -> remove cons0
6542           */
6543          SCIP_CALL( removeRedundantCons(scip, cons1, cons0, ndelconss) );
6544          break;
6545 
6546       case SCIP_SETPPCTYPE_COVERING:
6547          /* cons0: packing, cons1: covering
6548           * -> nothing can be deduced
6549           */
6550          break;
6551 
6552       default:
6553          SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1));
6554          return SCIP_INVALIDDATA;
6555       }
6556       break;
6557 
6558    case SCIP_SETPPCTYPE_COVERING:
6559       switch( consdata1->setppctype )
6560       {
6561       case SCIP_SETPPCTYPE_PARTITIONING:
6562       case SCIP_SETPPCTYPE_PACKING:
6563          /* cons0: covering, cons1: partitioning or packing
6564           * -> fix additional variables in cons1 to zero, remove cons1, convert cons0 into partitioning
6565           */
6566          SCIP_CALL( fixAdditionalVars(scip, cons0, cons1, cutoff, nfixedvars) );
6567          SCIP_CALL( setSetppcType(scip, cons0, SCIP_SETPPCTYPE_PARTITIONING) );
6568          SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6569          (*nchgsides)++;
6570          break;
6571 
6572       case SCIP_SETPPCTYPE_COVERING:
6573          /* cons0: covering, cons1: covering
6574           * -> remove cons1
6575           */
6576          SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6577          break;
6578 
6579       default:
6580          SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1));
6581          return SCIP_INVALIDDATA;
6582       }
6583       break;
6584 
6585    default:
6586       SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata0->setppctype, SCIPconsGetName(cons0));
6587       return SCIP_INVALIDDATA;
6588    }
6589 
6590    return SCIP_OKAY;
6591 }
6592 
6593 /** deletes redundant constraints */
6594 static
removeRedundantConstraints(SCIP * scip,SCIP_CONS ** conss,int firstchange,int chkind,SCIP_Bool * cutoff,int * nfixedvars,int * ndelconss,int * nchgsides)6595 SCIP_RETCODE removeRedundantConstraints(
6596    SCIP*                 scip,               /**< SCIP data structure */
6597    SCIP_CONS**           conss,              /**< constraint set */
6598    int                   firstchange,        /**< first constraint that changed since last pair preprocessing round */
6599    int                   chkind,             /**< index of constraint to check against all prior indices up to startind */
6600    SCIP_Bool*            cutoff,             /**< pointer to store whether a cutoff was found */
6601    int*                  nfixedvars,         /**< pointer to count number of fixed variables */
6602    int*                  ndelconss,          /**< pointer to count number of deleted constraints */
6603    int*                  nchgsides           /**< pointer to count number of changed left/right hand sides */
6604    )
6605 {
6606    SCIP_CONS* cons0;
6607    SCIP_CONSDATA* consdata0;
6608    uint64_t signature0;
6609    SCIP_Bool cons0changed;
6610    int c;
6611 
6612    assert(scip != NULL);
6613    assert(conss != NULL);
6614    assert(cutoff != NULL);
6615    assert(nfixedvars != NULL);
6616    assert(ndelconss != NULL);
6617    assert(nchgsides != NULL);
6618 
6619    *cutoff = FALSE;
6620 
6621    /* get the constraint to be checked against all prior constraints */
6622    cons0 = conss[chkind];
6623    assert(SCIPconsIsActive(cons0));
6624    assert(!SCIPconsIsModifiable(cons0));
6625 
6626    consdata0 = SCIPconsGetData(cons0);
6627    assert(consdata0 != NULL);
6628    assert(consdata0->nvars >= 1);
6629 
6630    /* sort the constraint cons0 */
6631    consdataSort(consdata0);
6632 
6633    /* get the bit signature of the constraint */
6634    signature0 = consdataGetSignature(consdata0);
6635 
6636    /* check constraint against all prior constraints */
6637    cons0changed = consdata0->changed;
6638    consdata0->changed = FALSE;
6639    for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff) && SCIPconsIsActive(cons0); ++c )
6640    {
6641       SCIP_CONS* cons1;
6642       SCIP_CONSDATA* consdata1;
6643       uint64_t signature1;
6644       uint64_t jointsignature;
6645       SCIP_Bool cons0iscontained;
6646       SCIP_Bool cons1iscontained;
6647       int v0;
6648       int v1;
6649 
6650       cons1 = conss[c];
6651 
6652       /* ignore inactive and modifiable constraints */
6653       if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
6654          continue;
6655 
6656       consdata1 = SCIPconsGetData(cons1);
6657       assert(consdata1 != NULL);
6658 
6659       /* sort the constraint cons1 */
6660       consdataSort(consdata1);
6661 
6662       /* get the bit signature of cons1 */
6663       signature1 = consdataGetSignature(consdata1);
6664 
6665       /* check (based on signature) if the two constraints are not included in each other */
6666       jointsignature = (signature0 | signature1);
6667       if( jointsignature != signature0 && jointsignature != signature1 )
6668          continue;
6669 
6670       /* check whether one constraint is really a subset of the other */
6671       cons0iscontained = (consdata0->nvars <= consdata1->nvars);
6672       cons1iscontained = (consdata1->nvars <= consdata0->nvars);
6673       v0 = 0;
6674       v1 = 0;
6675       while( v0 < consdata0->nvars && v1 < consdata1->nvars )
6676       {
6677          int index0;
6678          int index1;
6679 
6680          index0 = SCIPvarGetIndex(consdata0->vars[v0]);
6681          index1 = SCIPvarGetIndex(consdata1->vars[v1]);
6682          if( index0 < index1 )
6683          {
6684             cons0iscontained = FALSE;
6685             if( !cons1iscontained )
6686                break;
6687             for( v0++; v0 < consdata0->nvars && SCIPvarGetIndex(consdata0->vars[v0]) < index1; v0++ )
6688             {}
6689          }
6690          else if( index1 < index0 )
6691          {
6692             cons1iscontained = FALSE;
6693             if( !cons0iscontained )
6694                break;
6695             for( v1++; v1 < consdata1->nvars && SCIPvarGetIndex(consdata1->vars[v1]) < index0; v1++ )
6696             {}
6697          }
6698          else
6699          {
6700             v0++;
6701             v1++;
6702          }
6703       }
6704       cons0iscontained = cons0iscontained && (v0 == consdata0->nvars);
6705       cons1iscontained = cons1iscontained && (v1 == consdata1->nvars);
6706 
6707       if( cons0iscontained && cons1iscontained )
6708       {
6709          SCIPdebugMsg(scip, "setppc constraints <%s> and <%s> have identical variable sets\n",
6710             SCIPconsGetName(cons0), SCIPconsGetName(cons1));
6711          SCIPdebugPrintCons(scip, cons0, NULL);
6712          SCIPdebugPrintCons(scip, cons1, NULL);
6713 
6714          /* both constraints consists of the same variables */
6715          if( consdata0->setppctype == consdata1->setppctype )
6716          {
6717             /* both constraints are equal: update flags in cons0 and delete cons1 */
6718             SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6719          }
6720          else if( consdata0->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
6721          {
6722             /* the set partitioning constraint is stronger: remove the other one */
6723             SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6724          }
6725          else if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
6726          {
6727             /* the set partitioning constraint is stronger: remove the other one */
6728             SCIP_CALL( removeRedundantCons(scip, cons1, cons0, ndelconss) );
6729          }
6730          else
6731          {
6732             /* one is a covering, the other one a packing constraint: replace them by a single partitioning constraint */
6733             assert((consdata0->setppctype == SCIP_SETPPCTYPE_COVERING && consdata1->setppctype == SCIP_SETPPCTYPE_PACKING)
6734                || (consdata1->setppctype == SCIP_SETPPCTYPE_COVERING && consdata0->setppctype == SCIP_SETPPCTYPE_PACKING)); /*lint !e641*/
6735 
6736             /* change the type of cons0 */
6737             SCIP_CALL( setSetppcType(scip, cons0, SCIP_SETPPCTYPE_PARTITIONING) );
6738             (*nchgsides)++;
6739 
6740             /* delete cons1 */
6741             SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6742          }
6743       }
6744       else if( cons0iscontained )
6745       {
6746          /* cons0 is contained in cons1 */
6747          SCIPdebugMsg(scip, "setppc constraint <%s> is contained in <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
6748          SCIPdebugPrintCons(scip, cons0, NULL);
6749          SCIPdebugPrintCons(scip, cons1, NULL);
6750          SCIP_CALL( processContainedCons(scip, cons0, cons1, cutoff, nfixedvars, ndelconss, nchgsides) );
6751       }
6752       else if( cons1iscontained )
6753       {
6754          /* cons1 is contained in cons1 */
6755          SCIPdebugMsg(scip, "setppc constraint <%s> is contained in <%s>\n", SCIPconsGetName(cons1), SCIPconsGetName(cons0));
6756          SCIPdebugPrintCons(scip, cons0, NULL);
6757          SCIPdebugPrintCons(scip, cons1, NULL);
6758          SCIP_CALL( processContainedCons(scip, cons1, cons0, cutoff, nfixedvars, ndelconss, nchgsides) );
6759       }
6760    }
6761 
6762    return SCIP_OKAY;
6763 }
6764 
6765 /* perform deletion of variables in all constraints of the constraint handler */
6766 static
performVarDeletions(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss)6767 SCIP_RETCODE performVarDeletions(
6768    SCIP*                 scip,               /**< SCIP data structure */
6769    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6770    SCIP_CONS**           conss,              /**< array of constraints */
6771    int                   nconss              /**< number of constraints */
6772    )
6773 {
6774    SCIP_CONSDATA* consdata;
6775    int i;
6776    int v;
6777 
6778    assert(scip != NULL);
6779    assert(conshdlr != NULL);
6780    assert(conss != NULL);
6781    assert(nconss >= 0);
6782    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6783 
6784    /* iterate over all constraints */
6785    for( i = 0; i < nconss; i++ )
6786    {
6787       consdata = SCIPconsGetData(conss[i]);
6788 
6789       /* constraint is marked, that some of its variables were deleted */
6790       if( consdata->varsdeleted )
6791       {
6792          /* iterate over all variables of the constraint and delete marked variables */
6793          for( v = consdata->nvars - 1; v >= 0; v-- )
6794          {
6795             if( SCIPvarIsDeleted(consdata->vars[v]) )
6796             {
6797                SCIP_CALL( delCoefPos(scip, conss[i], v) );
6798             }
6799          }
6800          consdata->varsdeleted = FALSE;
6801       }
6802    }
6803 
6804    return SCIP_OKAY;
6805 }
6806 
6807 /** helper function to enforce constraints */
6808 static
enforceConstraint(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,int nusefulconss,SCIP_SOL * sol,SCIP_RESULT * result)6809 SCIP_RETCODE enforceConstraint(
6810    SCIP*                 scip,               /**< SCIP data structure */
6811    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6812    SCIP_CONS**           conss,              /**< constraints to process */
6813    int                   nconss,             /**< number of constraints */
6814    int                   nusefulconss,       /**< number of useful (non-obsolete) constraints to process */
6815    SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
6816    SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
6817    )
6818 {
6819    SCIP_Bool cutoff;
6820    SCIP_Bool separated;
6821    SCIP_Bool reduceddom;
6822    int c;
6823 
6824    assert(conshdlr != NULL);
6825    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6826    assert(nconss == 0 || conss != NULL);
6827    assert(result != NULL);
6828 
6829    SCIPdebugMsg(scip, "Enforcing %d set partitioning / packing / covering constraints for %s solution\n", nconss,
6830          sol == NULL ? "LP" : "relaxation");
6831 
6832    *result = SCIP_FEASIBLE;
6833 
6834    cutoff = FALSE;
6835    separated = FALSE;
6836    reduceddom = FALSE;
6837 
6838    /* check all useful set partitioning / packing / covering constraints for feasibility */
6839    for( c = 0; c < nusefulconss && !cutoff && !reduceddom; ++c )
6840    {
6841       SCIP_CALL( separateCons(scip, conss[c], sol, TRUE, &cutoff, &separated, &reduceddom) );
6842    }
6843 
6844    /* check all obsolete set partitioning / packing / covering constraints for feasibility */
6845    for( c = nusefulconss; c < nconss && !cutoff && !separated && !reduceddom; ++c )
6846    {
6847       SCIP_CALL( separateCons(scip, conss[c], sol, TRUE, &cutoff, &separated, &reduceddom) );
6848    }
6849 
6850 #ifdef VARUSES
6851 #ifdef BRANCHLP
6852    /* @todo also branch on relaxation solution */
6853    if( (sol == NULL) && !cutoff && !separated && !reduceddom )
6854    {
6855       /* if solution is not integral, choose a variable set to branch on */
6856       SCIP_CALL( branchLP(scip, conshdlr, result) );
6857       if( *result != SCIP_FEASIBLE )
6858          return SCIP_OKAY;
6859    }
6860 #endif
6861 #endif
6862 
6863    /* return the correct result */
6864    if( cutoff )
6865       *result = SCIP_CUTOFF;
6866    else if( separated )
6867       *result = SCIP_SEPARATED;
6868    else if( reduceddom )
6869       *result = SCIP_REDUCEDDOM;
6870 
6871    return SCIP_OKAY;
6872 }
6873 
6874 /*
6875  * upgrading of linear constraints
6876  */
6877 
6878 
6879 /** creates and captures a set partitioning / packing / covering constraint */
6880 static
createConsSetppc(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_SETPPCTYPE setppctype,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)6881 SCIP_RETCODE createConsSetppc(
6882    SCIP*                 scip,               /**< SCIP data structure */
6883    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
6884    const char*           name,               /**< name of constraint */
6885    int                   nvars,              /**< number of variables in the constraint */
6886    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
6887    SCIP_SETPPCTYPE       setppctype,         /**< type of constraint: set partitioning, packing, or covering constraint */
6888    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
6889                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
6890    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
6891                                               *   Usually set to TRUE. */
6892    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
6893                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
6894    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
6895                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
6896    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
6897                                               *   Usually set to TRUE. */
6898    SCIP_Bool             local,              /**< is constraint only valid locally?
6899                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6900    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
6901                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
6902                                               *   adds coefficients to this constraint. */
6903    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
6904                                               *   Usually set to FALSE. Set to TRUE for own cuts which
6905                                               *   are separated as constraints. */
6906    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
6907                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6908    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
6909                                               *   if it may be moved to a more global node?
6910                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6911    )
6912 {
6913    SCIP_CONSHDLR* conshdlr;
6914    SCIP_CONSDATA* consdata;
6915    SCIP_CONSHDLRDATA* conshdlrdata;
6916 
6917    assert(scip != NULL);
6918 
6919    /* find the set partitioning constraint handler */
6920    conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
6921    if( conshdlr == NULL )
6922    {
6923       SCIPerrorMessage("set partitioning / packing / covering constraint handler not found\n");
6924       return SCIP_INVALIDCALL;
6925    }
6926 
6927    /* create the constraint specific data */
6928    if( SCIPgetStage(scip) == SCIP_STAGE_PROBLEM )
6929    {
6930       /* create constraint in original problem */
6931       SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, setppctype) );
6932    }
6933    else
6934    {
6935       /* create constraint in transformed problem */
6936       SCIP_CALL( consdataCreateTransformed(scip, &consdata, nvars, vars, setppctype) );
6937    }
6938 
6939    /* create constraint */
6940    SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
6941          local, modifiable, dynamic, removable, stickingatnode) );
6942 
6943    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6944    assert(conshdlrdata != NULL);
6945 
6946    if( SCIPisTransformed(scip) && setppctype == SCIP_SETPPCTYPE_PARTITIONING )
6947    {
6948       ++(conshdlrdata->nsetpart);
6949       assert(conshdlrdata->nsetpart >= 0);
6950    }
6951 
6952    if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
6953    {
6954       /* get event handler */
6955       assert(conshdlrdata->eventhdlr != NULL);
6956 
6957       /* catch bound change events of variables */
6958       SCIP_CALL( catchAllEvents(scip, *cons, conshdlrdata->eventhdlr) );
6959    }
6960 
6961    return SCIP_OKAY;
6962 }
6963 
6964 /** creates and captures a normalized (with all coefficients +1) setppc constraint */
6965 static
createNormalizedSetppc(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,int mult,SCIP_SETPPCTYPE setppctype,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)6966 SCIP_RETCODE createNormalizedSetppc(
6967    SCIP*                 scip,               /**< SCIP data structure */
6968    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
6969    const char*           name,               /**< name of constraint */
6970    int                   nvars,              /**< number of variables in the constraint */
6971    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
6972    SCIP_Real*            vals,               /**< array with coefficients (+1.0 or -1.0) */
6973    int                   mult,               /**< multiplier on the coefficients(+1 or -1) */
6974    SCIP_SETPPCTYPE       setppctype,         /**< type of constraint: set partitioning, packing, or covering constraint */
6975    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
6976                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
6977    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
6978                                               *   Usually set to TRUE. */
6979    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
6980                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
6981    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
6982                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
6983    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
6984                                               *   Usually set to TRUE. */
6985    SCIP_Bool             local,              /**< is constraint only valid locally?
6986                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6987    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
6988                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
6989                                               *   adds coefficients to this constraint. */
6990    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
6991                                               *   Usually set to FALSE. Set to TRUE for own cuts which
6992                                               *   are separated as constraints. */
6993    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
6994                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6995    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
6996                                               *   if it may be moved to a more global node?
6997                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6998    )
6999 {
7000    SCIP_VAR** transvars;
7001    int v;
7002 
7003    assert(nvars == 0 || vars != NULL);
7004    assert(nvars == 0 || vals != NULL);
7005    assert(mult == +1 || mult == -1);
7006 
7007    /* get temporary memory */
7008    SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
7009 
7010    /* negate positive or negative variables */
7011    for( v = 0; v < nvars; ++v )
7012    {
7013       if( mult * vals[v] > 0.0 )
7014          transvars[v] = vars[v];
7015       else
7016       {
7017          SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
7018       }
7019       assert(transvars[v] != NULL);
7020    }
7021 
7022    /* create the constraint */
7023    SCIP_CALL( createConsSetppc(scip, cons, name, nvars, transvars, setppctype,
7024          initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
7025 
7026    /* release temporary memory */
7027    SCIPfreeBufferArray(scip, &transvars);
7028 
7029    return SCIP_OKAY;
7030 }
7031 
7032 /** check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint */
7033 static
SCIP_DECL_LINCONSUPGD(linconsUpgdSetppc)7034 SCIP_DECL_LINCONSUPGD(linconsUpgdSetppc)
7035 {  /*lint --e{715}*/
7036    assert(upgdcons != NULL);
7037    assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
7038 
7039    /* check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint
7040     * - all set partitioning / packing / covering constraints consist only of binary variables with a
7041     *   coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated):
7042     *        lhs     <= x1 + ... + xp - y1 - ... - yn <= rhs
7043     * - negating all variables y = (1-Y) with negative coefficients gives:
7044     *        lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n
7045     * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives:
7046     *        p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs
7047     * - a set partitioning constraint has left hand side of +1.0, and right hand side of +1.0 : x(S) == 1.0
7048     *    -> without negations:  lhs == rhs == 1 - n  or  lhs == rhs == p - 1
7049     * - a set packing constraint has left hand side of -infinity, and right hand side of +1.0 : x(S) <= 1.0
7050     *    -> without negations:  (lhs == -inf  and  rhs == 1 - n)  or  (lhs == p - 1  and  rhs = +inf)
7051     * - a set covering constraint has left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0
7052     *    -> without negations:  (lhs == 1 - n  and  rhs == +inf)  or  (lhs == -inf  and  rhs = p - 1)
7053     */
7054    if( nposbin + nnegbin + nposimplbin + nnegimplbin == nvars && ncoeffspone + ncoeffsnone == nvars )
7055    {
7056       int mult;
7057 
7058       if( SCIPisEQ(scip, lhs, rhs) && (SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) || SCIPisEQ(scip, lhs, ncoeffspone - 1.0)) )
7059       {
7060          SCIPdebugMsg(scip, "upgrading constraint <%s> to set partitioning constraint\n", SCIPconsGetName(cons));
7061 
7062          /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
7063          mult = SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) ? +1 : -1;
7064 
7065          /* create the set partitioning constraint (an automatically upgraded constraint is always unmodifiable) */
7066          assert(!SCIPconsIsModifiable(cons));
7067          SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult,
7068                SCIP_SETPPCTYPE_PARTITIONING,
7069                SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7070                SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
7071                SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
7072                SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7073       }
7074       else if( (SCIPisInfinity(scip, -lhs) && SCIPisEQ(scip, rhs, 1.0 - ncoeffsnone))
7075          || (SCIPisEQ(scip, lhs, ncoeffspone - 1.0) && SCIPisInfinity(scip, rhs)) )
7076       {
7077          SCIPdebugMsg(scip, "upgrading constraint <%s> to set packing constraint\n", SCIPconsGetName(cons));
7078 
7079          /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
7080          mult = SCIPisInfinity(scip, -lhs) ? +1 : -1;
7081 
7082          /* create the set packing constraint (an automatically upgraded constraint is always unmodifiable) */
7083          assert(!SCIPconsIsModifiable(cons));
7084          SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult,
7085                SCIP_SETPPCTYPE_PACKING,
7086                SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7087                SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
7088                SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
7089                SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7090       }
7091       else if( (SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, rhs))
7092          || (SCIPisInfinity(scip, -lhs) && SCIPisEQ(scip, rhs, ncoeffspone - 1.0)) )
7093       {
7094          SCIPdebugMsg(scip, "upgrading constraint <%s> to set covering constraint\n", SCIPconsGetName(cons));
7095 
7096          /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
7097          mult = SCIPisInfinity(scip, rhs) ? +1 : -1;
7098 
7099          /* create the set covering constraint (an automatically upgraded constraint is always unmodifiable) */
7100          assert(!SCIPconsIsModifiable(cons));
7101          SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult,
7102                SCIP_SETPPCTYPE_COVERING,
7103                SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7104                SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
7105                SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
7106                SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7107       }
7108    }
7109 
7110    return SCIP_OKAY;
7111 }
7112 
7113 /** tries to upgrade a quadratic constraint to a setpacking constraint */
7114 static
SCIP_DECL_QUADCONSUPGD(quadraticUpgdSetppc)7115 SCIP_DECL_QUADCONSUPGD(quadraticUpgdSetppc)
7116 {
7117    SCIP_QUADVARTERM* quadvarterms;
7118    SCIP_BILINTERM* term;
7119    SCIP_VAR* vars[2];
7120    SCIP_Real coefx;
7121    SCIP_Real coefy;
7122    SCIP_Real rhs;
7123 
7124    assert( scip != NULL );
7125    assert( cons != NULL );
7126    assert( nupgdconss != NULL );
7127    assert( upgdconss  != NULL );
7128    assert( ! SCIPconsIsModifiable(cons) );
7129    assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "quadratic") == 0 );
7130 
7131    *nupgdconss = 0;
7132 
7133    SCIPdebugMsg(scip, "try to upgrade quadratic constraint <%s> to setpacking constraint ...\n", SCIPconsGetName(cons));
7134    SCIPdebugPrintCons(scip, cons, NULL);
7135 
7136    /* cannot currently handle linear part */
7137    if( SCIPgetNLinearVarsQuadratic(scip, cons) > 0 )
7138       return SCIP_OKAY;
7139 
7140    /* need only one bilinear term */
7141    if( SCIPgetNBilinTermsQuadratic(scip, cons) != 1 )
7142       return SCIP_OKAY;
7143 
7144    /* need exactly two quadratic variables */
7145    if( SCIPgetNQuadVarTermsQuadratic(scip, cons) != 2 )
7146       return SCIP_OKAY;
7147 
7148    /* get bilinear term */
7149    term = SCIPgetBilinTermsQuadratic(scip, cons);
7150    if( SCIPisZero(scip, term->coef) )
7151       return SCIP_OKAY;
7152 
7153    /* check types */
7154    if( SCIPvarGetType(term->var1) != SCIP_VARTYPE_BINARY || SCIPvarGetType(term->var2) != SCIP_VARTYPE_BINARY )
7155       return SCIP_OKAY;
7156 
7157    /* left and right hand side need to be equal
7158     * @todo we could also handle inequalities
7159     */
7160    rhs = SCIPgetRhsQuadratic(scip, cons);
7161    if( SCIPisInfinity(scip, rhs) || !SCIPisEQ(scip, SCIPgetLhsQuadratic(scip, cons), rhs) )
7162       return SCIP_OKAY;
7163 
7164    quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, cons);
7165 
7166    coefx = quadvarterms[0].lincoef + quadvarterms[0].sqrcoef;  /* for binary variables, we can treat sqr coef as lin coef */
7167    coefy = quadvarterms[1].lincoef + quadvarterms[0].sqrcoef;  /* for binary variables, we can treat sqr coef as lin coef */
7168 
7169    /* divide constraint by coefficient of x*y */
7170    coefx /= term->coef;
7171    coefy /= term->coef;
7172    rhs   /= term->coef;
7173 
7174    /* constraint is now of the form coefx * x + coefy * y + x * y == rhs
7175     * we can rewrite as (x + coefy) * (y + coefx) == rhs + coefx * coefy
7176     */
7177 
7178    /* we can only upgrade if coefx and coefy are 0 or -1 and rhs == -coefx * coefy */
7179    if( !SCIPisZero(scip, coefx) && !SCIPisEQ(scip, coefx, -1.0) )
7180       return SCIP_OKAY;
7181    if( !SCIPisZero(scip, coefy) && !SCIPisEQ(scip, coefy, -1.0) )
7182       return SCIP_OKAY;
7183    if( !SCIPisEQ(scip, rhs, -coefx * coefy) )
7184       return SCIP_OKAY;
7185 
7186    if( SCIPisZero(scip, coefy) )
7187    {
7188       vars[0] = quadvarterms[0].var;
7189    }
7190    else
7191    {
7192       assert(SCIPisEQ(scip, coefy, -1.0));
7193       /* x - 1 = -(1-x) = -(~x) */
7194       SCIP_CALL( SCIPgetNegatedVar(scip, quadvarterms[0].var, &vars[0]) );
7195    }
7196    if( SCIPisZero(scip, coefx) )
7197    {
7198       vars[1] = quadvarterms[1].var;
7199    }
7200    else
7201    {
7202       assert(SCIPisEQ(scip, coefx, -1.0));
7203       /* y - 1 = -(1 - y) = -(~y) */
7204       SCIP_CALL( SCIPgetNegatedVar(scip, quadvarterms[1].var, &vars[1]) );
7205    }
7206 
7207    /* constraint is now of the form  vars[0] * vars[1] == 0 */
7208 
7209    SCIPdebugMsg(scip, "constraint <%s> can be upgraded ...\n", SCIPconsGetName(cons));
7210 
7211    /* vars[0] + vars[1] <= 1 */
7212    SCIP_CALL( SCIPcreateConsSetpack(scip, &upgdconss[0], SCIPconsGetName(cons), 2, vars,
7213          SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7214          SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),  SCIPconsIsLocal(cons),
7215          SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7216    SCIPdebugPrintCons(scip, upgdconss[0], NULL);
7217 
7218    ++(*nupgdconss);
7219 
7220    return SCIP_OKAY;
7221 } /*lint !e715*/
7222 
7223 
7224 /*
7225  * Callback methods of constraint handler
7226  */
7227 
7228 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
7229 static
SCIP_DECL_CONSHDLRCOPY(conshdlrCopySetppc)7230 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySetppc)
7231 {  /*lint --e{715}*/
7232    assert(scip != NULL);
7233    assert(conshdlr != NULL);
7234    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7235 
7236    /* call inclusion method of constraint handler */
7237    SCIP_CALL( SCIPincludeConshdlrSetppc(scip) );
7238 
7239    *valid = TRUE;
7240 
7241    return SCIP_OKAY;
7242 }
7243 
7244 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
7245 static
SCIP_DECL_CONSFREE(consFreeSetppc)7246 SCIP_DECL_CONSFREE(consFreeSetppc)
7247 {  /*lint --e{715}*/
7248    SCIP_CONSHDLRDATA* conshdlrdata;
7249 
7250    assert(conshdlr != NULL);
7251    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7252    assert(scip != NULL);
7253 
7254    /* free constraint handler data */
7255    conshdlrdata = SCIPconshdlrGetData(conshdlr);
7256    assert(conshdlrdata != NULL);
7257    SCIP_CALL( conshdlrdataFree(scip, &conshdlrdata) );
7258 
7259    SCIPconshdlrSetData(conshdlr, NULL);
7260 
7261    return SCIP_OKAY;
7262 }
7263 
7264 
7265 /** initialization method of constraint handler (called after problem was transformed) */
7266 static
SCIP_DECL_CONSINIT(consInitSetppc)7267 SCIP_DECL_CONSINIT(consInitSetppc)
7268 {  /*lint --e{715}*/
7269    SCIP_CONSHDLRDATA* conshdlrdata;
7270 
7271    assert(conshdlr != NULL);
7272    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7273    assert(scip != NULL);
7274 
7275    /* free constraint handler data */
7276    conshdlrdata = SCIPconshdlrGetData(conshdlr);
7277    assert(conshdlrdata != NULL);
7278 
7279    conshdlrdata->noldfixedvars = 0;
7280    conshdlrdata->noldimpls = 0;
7281    conshdlrdata->noldcliques = 0;
7282    conshdlrdata->noldupgrs = 0;
7283    conshdlrdata->nclqpresolve = 0;
7284    conshdlrdata->updatedsetppctype = FALSE;
7285    conshdlrdata->enablecliquelifting = TRUE;
7286 
7287    return SCIP_OKAY;
7288 }
7289 
7290 
7291 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
7292 static
SCIP_DECL_CONSEXITPRE(consExitpreSetppc)7293 SCIP_DECL_CONSEXITPRE(consExitpreSetppc)
7294 {  /*lint --e{715}*/
7295    int c;
7296 
7297    assert(scip != NULL);
7298    assert(conshdlr != NULL);
7299 
7300    for( c = 0; c < nconss; ++c )
7301    {
7302       if( !SCIPconsIsDeleted(conss[c]) )
7303       {
7304          /* we are not allowed to detect infeasibility in the exitpre stage */
7305          SCIP_CALL( applyFixings(scip, conss[c], NULL, NULL, NULL, NULL) );
7306       }
7307    }
7308 
7309    return SCIP_OKAY;
7310 }
7311 
7312 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
7313 static
SCIP_DECL_CONSEXITSOL(consExitsolSetppc)7314 SCIP_DECL_CONSEXITSOL(consExitsolSetppc)
7315 {  /*lint --e{715}*/
7316    SCIP_CONSDATA* consdata;
7317    int c;
7318 
7319    /* release the rows of all constraints */
7320    for( c = 0; c < nconss; ++c )
7321    {
7322       consdata = SCIPconsGetData(conss[c]);
7323       assert(consdata != NULL);
7324 
7325       if( consdata->row != NULL )
7326       {
7327          SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
7328       }
7329    }
7330 
7331    return SCIP_OKAY;
7332 }
7333 
7334 
7335 /** frees specific constraint data */
7336 static
SCIP_DECL_CONSDELETE(consDeleteSetppc)7337 SCIP_DECL_CONSDELETE(consDeleteSetppc)
7338 {  /*lint --e{715}*/
7339    SCIP_CONSHDLRDATA* conshdlrdata;
7340 
7341    assert(conshdlr != NULL);
7342    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7343 
7344    /* get event handler */
7345    conshdlrdata = SCIPconshdlrGetData(conshdlr);
7346    assert(conshdlrdata != NULL);
7347    assert(conshdlrdata->eventhdlr != NULL);
7348 
7349    if( SCIPisTransformed(scip) )
7350    {
7351       if( (SCIP_SETPPCTYPE)((*consdata)->setppctype) == SCIP_SETPPCTYPE_PARTITIONING )
7352       {
7353          --(conshdlrdata->nsetpart);
7354          assert(conshdlrdata->nsetpart >= 0);
7355       }
7356    }
7357 
7358    /* if constraint belongs to transformed problem space, drop bound change events on variables */
7359    if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
7360    {
7361       SCIP_CALL( dropAllEvents(scip, cons, conshdlrdata->eventhdlr) );
7362    }
7363 
7364    /* free setppc constraint data */
7365    SCIP_CALL( consdataFree(scip, consdata) );
7366 
7367    return SCIP_OKAY;
7368 }
7369 
7370 
7371 /** transforms constraint data into data belonging to the transformed problem */
7372 static
SCIP_DECL_CONSTRANS(consTransSetppc)7373 SCIP_DECL_CONSTRANS(consTransSetppc)
7374 {  /*lint --e{715}*/
7375    SCIP_CONSHDLRDATA* conshdlrdata;
7376    SCIP_CONSDATA* sourcedata;
7377    SCIP_CONSDATA* targetdata;
7378 
7379    /*debugMsg(scip, "Trans method of setppc constraints\n");*/
7380 
7381    assert(conshdlr != NULL);
7382    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7383    assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
7384    assert(sourcecons != NULL);
7385    assert(targetcons != NULL);
7386 
7387    /* get event handler */
7388    conshdlrdata = SCIPconshdlrGetData(conshdlr);
7389    assert(conshdlrdata != NULL);
7390    assert(conshdlrdata->eventhdlr != NULL);
7391 
7392    sourcedata = SCIPconsGetData(sourcecons);
7393    assert(sourcedata != NULL);
7394    assert(sourcedata->row == NULL);  /* in original problem, there cannot be LP rows */
7395 
7396    /* create constraint data for target constraint */
7397    SCIP_CALL( consdataCreateTransformed(scip, &targetdata, sourcedata->nvars, sourcedata->vars,
7398          (SCIP_SETPPCTYPE)sourcedata->setppctype) );
7399 
7400    /* create target constraint */
7401    SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
7402          SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
7403          SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
7404          SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
7405          SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
7406 
7407    if( (SCIP_SETPPCTYPE)sourcedata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
7408    {
7409       ++(conshdlrdata->nsetpart);
7410       assert(conshdlrdata->nsetpart >= 0);
7411    }
7412 
7413    /* catch bound change events of variables */
7414    SCIP_CALL( catchAllEvents(scip, *targetcons, conshdlrdata->eventhdlr) );
7415 
7416    return SCIP_OKAY;
7417 }
7418 
7419 
7420 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
7421 static
SCIP_DECL_CONSINITLP(consInitlpSetppc)7422 SCIP_DECL_CONSINITLP(consInitlpSetppc)
7423 {  /*lint --e{715}*/
7424    int c;
7425 
7426    *infeasible = FALSE;
7427 
7428    for( c = 0; c < nconss && !(*infeasible); ++c )
7429    {
7430       assert(SCIPconsIsInitial(conss[c]));
7431       SCIP_CALL( addCut(scip, conss[c], infeasible) );
7432    }
7433 
7434    return SCIP_OKAY;
7435 }
7436 
7437 
7438 /** separation method of constraint handler for LP solutions */
7439 static
SCIP_DECL_CONSSEPALP(consSepalpSetppc)7440 SCIP_DECL_CONSSEPALP(consSepalpSetppc)
7441 {  /*lint --e{715}*/
7442    SCIP_Bool cutoff;
7443    SCIP_Bool separated;
7444    SCIP_Bool reduceddom;
7445    int c;
7446 
7447    assert(conshdlr != NULL);
7448    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7449    assert(nconss == 0 || conss != NULL);
7450    assert(result != NULL);
7451 
7452    SCIPdebugMsg(scip, "separating %d/%d set partitioning / packing / covering constraints\n", nusefulconss, nconss);
7453 
7454    *result = SCIP_DIDNOTFIND;
7455 
7456    cutoff = FALSE;
7457    separated = FALSE;
7458    reduceddom = FALSE;
7459 
7460    /* check all useful set partitioning / packing / covering constraints for feasibility */
7461    for( c = 0; c < nusefulconss && !cutoff; ++c )
7462    {
7463       SCIP_CALL( separateCons(scip, conss[c], NULL, TRUE, &cutoff, &separated, &reduceddom) );
7464    }
7465 
7466    /* combine set partitioning / packing / covering constraints to get more cuts */
7467    /**@todo further cuts of set partitioning / packing / covering constraints */
7468 
7469    /* return the correct result */
7470    if( cutoff )
7471       *result = SCIP_CUTOFF;
7472    else if( reduceddom )
7473       *result = SCIP_REDUCEDDOM;
7474    else if( separated )
7475       *result = SCIP_SEPARATED;
7476 
7477    return SCIP_OKAY;
7478 }
7479 
7480 
7481 /** separation method of constraint handler for arbitrary primal solutions */
7482 static
SCIP_DECL_CONSSEPASOL(consSepasolSetppc)7483 SCIP_DECL_CONSSEPASOL(consSepasolSetppc)
7484 {  /*lint --e{715}*/
7485    SCIP_Bool cutoff;
7486    SCIP_Bool separated;
7487    SCIP_Bool reduceddom;
7488    int c;
7489 
7490    assert(conshdlr != NULL);
7491    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7492    assert(nconss == 0 || conss != NULL);
7493    assert(result != NULL);
7494 
7495    SCIPdebugMsg(scip, "separating %d/%d set partitioning / packing / covering constraints\n", nusefulconss, nconss);
7496 
7497    *result = SCIP_DIDNOTFIND;
7498 
7499    cutoff = FALSE;
7500    separated = FALSE;
7501    reduceddom = FALSE;
7502 
7503    /* check all useful set partitioning / packing / covering constraints for feasibility */
7504    for( c = 0; c < nusefulconss && !cutoff; ++c )
7505    {
7506       SCIP_CALL( separateCons(scip, conss[c], sol, FALSE, &cutoff, &separated, &reduceddom) );
7507    }
7508 
7509    /* combine set partitioning / packing / covering constraints to get more cuts */
7510    /**@todo further cuts of set partitioning / packing / covering constraints */
7511 
7512    /* return the correct result */
7513    if( cutoff )
7514       *result = SCIP_CUTOFF;
7515    else if( reduceddom )
7516       *result = SCIP_REDUCEDDOM;
7517    else if( separated )
7518       *result = SCIP_SEPARATED;
7519 
7520    return SCIP_OKAY;
7521 }
7522 
7523 
7524 #ifdef VARUSES
7525 #ifdef BRANCHLP
7526 /** if fractional variables exist, chooses a set S of them and branches on (i) x(S) == 0, and (ii) x(S) >= 1 */
7527 static
branchLP(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_RESULT * result)7528 SCIP_RETCODE branchLP(
7529    SCIP*                 scip,               /**< SCIP data structure */
7530    SCIP_CONSHDLR*        conshdlr,           /**< set partitioning / packing / covering constraint handler */
7531    SCIP_RESULT*          result              /**< pointer to store the result SCIP_BRANCHED, if branching was applied */
7532    )
7533 {
7534    SCIP_CONSHDLRDATA* conshdlrdata;
7535    SCIP_INTARRAY* varuses;
7536    SCIP_VAR** lpcands;
7537    SCIP_VAR** sortcands;
7538    SCIP_VAR* var;
7539    SCIP_Real branchweight;
7540    SCIP_Real solval;
7541    int* uses;
7542    int nlpcands;
7543    int nsortcands;
7544    int nselcands;
7545    int numuses;
7546    int i;
7547    int j;
7548 
7549    /**@todo use a better set partitioning / packing / covering branching on LP solution (use SOS branching) */
7550 
7551    assert(conshdlr != NULL);
7552    assert(result != NULL);
7553 
7554    conshdlrdata = SCIPconshdlrGetData(conshdlr);
7555    assert(conshdlrdata != NULL);
7556 
7557    varuses = conshdlrdata->varuses;
7558    assert(varuses != NULL);
7559 
7560    /* get fractional variables */
7561    SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, NULL, &nlpcands, NULL, NULL) );
7562    if( nlpcands == 0 )
7563       return SCIP_OKAY;
7564 
7565    assert(MINBRANCHWEIGHT <= MAXBRANCHWEIGHT);
7566 
7567    /* get temporary memory */
7568    SCIP_CALL( SCIPallocBufferArray(scip, &sortcands, nlpcands) );
7569    SCIP_CALL( SCIPallocBufferArray(scip, &uses, nlpcands) );
7570 
7571    /* sort fractional variables by number of uses in enabled set partitioning / packing / covering constraints */
7572    nsortcands = 0;
7573    for( i = 0; i < nlpcands; ++i )
7574    {
7575       var = lpcands[i];
7576       numuses = SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var));
7577       if( numuses > 0 )
7578       {
7579          for( j = nsortcands; j > 0 && numuses > uses[j-1]; --j )
7580          {
7581             sortcands[j] = sortcands[j-1];
7582             uses[j] = uses[j-1];
7583          }
7584          assert(0 <= j && j <= nsortcands);
7585          sortcands[j] = var;
7586          uses[j] = numuses;
7587          nsortcands++;
7588       }
7589    }
7590    assert(nsortcands <= nlpcands);
7591 
7592    /* if none of the fractional variables is member of a set partitioning / packing / covering constraint,
7593     * we are not responsible for doing the branching
7594     */
7595    if( nsortcands > 0 )
7596    {
7597       SCIP_Real cumprio = 0.0;
7598       SCIP_Real minprio = SCIP_INVALID;
7599       SCIP_Real minestzero = SCIP_INVALID;
7600       SCIP_Real minestone = SCIP_INVALID;
7601       SCIP_Real tmp;
7602 
7603       /* select the first variables from the sorted candidate list, until MAXBRANCHWEIGHT is reached;
7604        * then choose one less
7605        */
7606       branchweight = 0.0;
7607       solval = 0.0;
7608       for( nselcands = 0; nselcands < nsortcands; ++nselcands )
7609       {
7610          solval = SCIPgetVarSol(scip, sortcands[nselcands]);
7611          assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0));
7612          branchweight += solval;
7613 
7614 	 /* did we exceed the maximal weight */
7615 	 if( branchweight > MAXBRANCHWEIGHT )
7616 	    break;
7617 
7618 	 /* @todo instead of taking the minimum into account try other variants like the maximum and the average */
7619 	 /* calculate priorities and estimates by adding up/taking the minimum of all single priorities/estimates */
7620 	 cumprio += SCIPcalcNodeselPriority(scip, sortcands[nselcands], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
7621 	 tmp = SCIPcalcNodeselPriority(scip, sortcands[nselcands], SCIP_BRANCHDIR_UPWARDS, 1.0);
7622 	 minprio = MIN(minprio, tmp);
7623 	 tmp = SCIPcalcChildEstimate(scip, sortcands[nselcands], 0.0);;
7624 	 minestzero = MIN(minestzero, tmp);
7625 	 tmp = SCIPcalcChildEstimate(scip, sortcands[nselcands], 1.0);;
7626 	 minestone = MIN(minestone, tmp);
7627       }
7628       assert(minestzero != SCIP_INVALID); /*lint !e777*/
7629       assert(minestone != SCIP_INVALID); /*lint !e777*/
7630       assert(minprio != SCIP_INVALID); /*lint !e777*/
7631       assert(nselcands > 0);
7632       branchweight -= solval;
7633 
7634       /* check, if we accumulated at least MIN and at most MAXBRANCHWEIGHT weight */
7635       if( MINBRANCHWEIGHT <= branchweight && branchweight <= MAXBRANCHWEIGHT )
7636       {
7637          SCIP_NODE* node;
7638 
7639          /* perform the binary set branching on the selected variables */
7640          assert(1 <= nselcands && nselcands <= nlpcands);
7641 
7642          /* create left child, fix x_i = 0 for all i \in S */
7643          SCIP_CALL( SCIPcreateChild(scip, &node, cumprio, minestzero) );
7644          for( i = 0; i < nselcands; ++i )
7645          {
7646             SCIP_CALL( SCIPchgVarUbNode(scip, node, sortcands[i], 0.0) );
7647          }
7648 
7649          /* create right child: add constraint x(S) >= 1 */
7650          SCIP_CALL( SCIPcreateChild(scip, &node, minprio, minestone) );
7651          if( nselcands == 1 )
7652          {
7653             /* only one candidate selected: fix it to 1.0 */
7654             SCIPdebugMsg(scip, "fixing variable <%s> to 1.0 in right child node\n", SCIPvarGetName(sortcands[0]));
7655             SCIP_CALL( SCIPchgVarLbNode(scip, node, sortcands[0], 1.0) );
7656          }
7657          else
7658          {
7659             SCIP_CONS* newcons;
7660             char name[SCIP_MAXSTRLEN];
7661 
7662             /* add set covering constraint x(S) >= 1 */
7663             (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "BSB%" SCIP_LONGINT_FORMAT, SCIPgetNTotalNodes(scip));
7664 
7665             SCIP_CALL( SCIPcreateConsSetcover(scip, &newcons, name, nselcands, sortcands,
7666                   FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
7667             SCIP_CALL( SCIPaddConsNode(scip, node, newcons, NULL) );
7668             SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7669          }
7670 
7671          *result = SCIP_BRANCHED;
7672 
7673 #ifdef SCIP_DEBUG
7674          SCIPdebugMsg(scip, "binary set branching: nselcands=%d/%d, weight(S)=%g, A={", nselcands, nlpcands, branchweight);
7675          for( i = 0; i < nselcands; ++i )
7676             SCIPdebugMsgPrint(scip, " %s[%g]", SCIPvarGetName(sortcands[i]), SCIPgetSolVal(scip, NULL, sortcands[i]));
7677          SCIPdebugMsgPrint(scip, " }\n");
7678 #endif
7679       }
7680    }
7681 
7682    /* free temporary memory */
7683    SCIPfreeBufferArray(scip, &uses);
7684    SCIPfreeBufferArray(scip, &sortcands);
7685 
7686    return SCIP_OKAY;
7687 }
7688 #endif
7689 
7690 /** if unfixed variables exist, chooses a set S of them and creates |S|+1 child nodes:
7691  *   - for each variable i from S, create child node with x_0 = ... = x_i-1 = 0, x_i = 1
7692  *   - create an additional child node x_0 = ... = x_n-1 = 0
7693  */
7694 static
branchPseudo(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_RESULT * result)7695 SCIP_RETCODE branchPseudo(
7696    SCIP*                 scip,               /**< SCIP data structure */
7697    SCIP_CONSHDLR*        conshdlr,           /**< set partitioning / packing / covering constraint handler */
7698    SCIP_RESULT*          result              /**< pointer to store the result SCIP_BRANCHED, if branching was applied */
7699    )
7700 {
7701    SCIP_CONSHDLRDATA* conshdlrdata;
7702    SCIP_INTARRAY* varuses;
7703    SCIP_VAR** pseudocands;
7704    SCIP_VAR** branchcands;
7705    SCIP_VAR* var;
7706    SCIP_NODE* node;
7707    int* canduses;
7708    int npseudocands;
7709    int maxnbranchcands;
7710    int nbranchcands;
7711    int uses;
7712    int i;
7713    int j;
7714 
7715    /**@todo use a better set partitioning / packing / covering branching on pseudo solution (use SOS branching) */
7716 
7717    assert(conshdlr != NULL);
7718    assert(result != NULL);
7719 
7720    conshdlrdata = SCIPconshdlrGetData(conshdlr);
7721    assert(conshdlrdata != NULL);
7722 
7723    /* check, if pseudo branching is disabled */
7724    if( conshdlrdata->npseudobranches <= 1 )
7725       return SCIP_OKAY;
7726 
7727    /* get fractional variables */
7728    SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, NULL, &npseudocands) );
7729    if( npseudocands == 0 )
7730       return SCIP_OKAY;
7731 
7732    varuses = conshdlrdata->varuses;
7733    assert(varuses != NULL);
7734 
7735    /* choose the maximal number of branching variables */
7736    maxnbranchcands = conshdlrdata->npseudobranches-1;
7737    assert(maxnbranchcands >= 1);
7738 
7739    /* get temporary memory */
7740    SCIP_CALL( SCIPallocBufferArray(scip, &branchcands, maxnbranchcands) );
7741    SCIP_CALL( SCIPallocBufferArray(scip, &canduses, maxnbranchcands) );
7742 
7743    /* sort unfixed variables by number of uses in enabled set partitioning / packing / covering constraints */
7744    nbranchcands = 0;
7745    for( i = 0; i < npseudocands; ++i )
7746    {
7747       var = pseudocands[i];
7748       uses = SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var));
7749       if( uses > 0 )
7750       {
7751          if( nbranchcands < maxnbranchcands || uses > canduses[nbranchcands-1] )
7752          {
7753             for( j = MIN(nbranchcands, maxnbranchcands-1); j > 0 && uses > canduses[j-1]; --j )
7754             {
7755                branchcands[j] = branchcands[j-1];
7756                canduses[j] = canduses[j-1];
7757             }
7758             assert(0 <= j && j <= nbranchcands && j < maxnbranchcands);
7759             branchcands[j] = var;
7760             canduses[j] = uses;
7761             if( nbranchcands < maxnbranchcands )
7762                nbranchcands++;
7763          }
7764       }
7765    }
7766    assert(nbranchcands <= maxnbranchcands);
7767 
7768    /* if none of the unfixed variables is member of a set partitioning / packing / covering constraint,
7769     * we are not responsible for doing the branching
7770     */
7771    if( nbranchcands > 0 )
7772    {
7773       SCIP_Real* estone;
7774       SCIP_Real minestzero = SCIP_INVALID;
7775       SCIP_Real tmp;
7776 
7777       SCIP_CALL( SCIPallocBufferArray(scip, &estone, nbranchcands) );
7778 
7779       /* @todo instead of taking the minimum into account try other variants like the maximum and the average */
7780       /* @todo calculate priorities instead of setting it to the number of branching candidates */
7781       /* calculate estimates by taking the minimum over all single estimates */
7782       for( i = 0; i < nbranchcands; ++i )
7783       {
7784 	 tmp = SCIPcalcChildEstimate(scip, branchcands[i], 0.0);;
7785 	 minestzero = MIN(minestzero, tmp);
7786 	 estone[i] = SCIPcalcChildEstimate(scip, branchcands[i], 1.0);
7787       }
7788       assert(minestzero != SCIP_INVALID); /*lint !e777*/
7789 
7790       /* branch on the first part of the sorted candidates:
7791        * - for each of these variables i, create a child node x_0 = ... = x_i-1 = 0, x_i = 1
7792        * - create an additional child node x_0 = ... = x_n-1 = 0
7793        */
7794       for( i = 0; i < nbranchcands; ++i )
7795       {
7796          /* create child with x_0 = ... = x_i-1 = 0, x_i = 1 */
7797          SCIP_CALL( SCIPcreateChild(scip, &node, (SCIP_Real)nbranchcands, MIN(minestzero, estone[i])) );
7798          for( j = 0; j < i; ++j )
7799          {
7800             SCIP_CALL( SCIPchgVarUbNode(scip, node, branchcands[j], 0.0) );
7801          }
7802          SCIP_CALL( SCIPchgVarLbNode(scip, node, branchcands[i], 1.0) );
7803       }
7804       /* create child with x_0 = ... = x_n = 0 */
7805       SCIP_CALL( SCIPcreateChild(scip, &node, (SCIP_Real)nbranchcands, minestzero) );
7806       for( i = 0; i < nbranchcands; ++i )
7807       {
7808          SCIP_CALL( SCIPchgVarUbNode(scip, node, branchcands[i], 0.0) );
7809       }
7810 
7811       *result = SCIP_BRANCHED;
7812 
7813       SCIPfreeBufferArray(scip, &estone);
7814 
7815 #ifdef SCIP_DEBUG
7816       {
7817          int nchildren;
7818          SCIP_CALL( SCIPgetChildren(scip, NULL, &nchildren) );
7819          SCIPdebugMsg(scip, "branched on pseudo solution: %d children\n", nchildren);
7820       }
7821 #endif
7822    }
7823 
7824    /* free temporary memory */
7825    SCIPfreeBufferArray(scip, &canduses);
7826    SCIPfreeBufferArray(scip, &branchcands);
7827 
7828    return SCIP_OKAY;
7829 }
7830 #endif
7831 
7832 
7833 /** constraint enforcing method of constraint handler for LP solutions */
7834 static
SCIP_DECL_CONSENFOLP(consEnfolpSetppc)7835 SCIP_DECL_CONSENFOLP(consEnfolpSetppc)
7836 {  /*lint --e{715}*/
7837    SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
7838 
7839    return SCIP_OKAY;
7840 }
7841 
7842 
7843 /** constraint enforcing method of constraint handler for relaxation solutions */
7844 static
SCIP_DECL_CONSENFORELAX(consEnforelaxSetppc)7845 SCIP_DECL_CONSENFORELAX(consEnforelaxSetppc)
7846 {  /*lint --e{715}*/
7847    SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
7848 
7849    return SCIP_OKAY;
7850 }
7851 
7852 
7853 /** constraint enforcing method of constraint handler for pseudo solutions */
7854 static
SCIP_DECL_CONSENFOPS(consEnfopsSetppc)7855 SCIP_DECL_CONSENFOPS(consEnfopsSetppc)
7856 {  /*lint --e{715}*/
7857    SCIP_Bool cutoff;
7858    SCIP_Bool infeasible;
7859    SCIP_Bool reduceddom;
7860    SCIP_Bool solvelp;
7861    int c;
7862 
7863    assert(conshdlr != NULL);
7864    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7865    assert(nconss == 0 || conss != NULL);
7866    assert(result != NULL);
7867 
7868    /* if the solution is infeasible anyway due to objective value, skip the constraint processing and branch directly */
7869 #ifdef VARUSES
7870    if( objinfeasible )
7871    {
7872       *result = SCIP_DIDNOTRUN;
7873       SCIP_CALL( branchPseudo(scip, conshdlr, result) );
7874       return SCIP_OKAY;
7875    }
7876 #endif
7877 
7878    SCIPdebugMsg(scip, "pseudo enforcing %d set partitioning / packing / covering constraints\n", nconss);
7879 
7880    *result = SCIP_FEASIBLE;
7881 
7882    cutoff = FALSE;
7883    infeasible = FALSE;
7884    reduceddom = FALSE;
7885    solvelp = FALSE;
7886 
7887    /* check all set partitioning / packing / covering constraints for feasibility */
7888    for( c = 0; c < nconss && !cutoff && !reduceddom && !solvelp; ++c )
7889    {
7890       SCIP_CALL( enforcePseudo(scip, conss[c], &cutoff, &infeasible, &reduceddom, &solvelp) );
7891    }
7892 
7893    if( cutoff )
7894       *result = SCIP_CUTOFF;
7895    else if( reduceddom )
7896       *result = SCIP_REDUCEDDOM;
7897    else if( solvelp )
7898       *result = SCIP_SOLVELP;
7899    else if( infeasible )
7900    {
7901       *result = SCIP_INFEASIBLE;
7902 
7903 #ifdef VARUSES
7904       /* at least one constraint is violated by pseudo solution and we didn't find a better way to resolve this:
7905        * -> branch on pseudo solution
7906        */
7907       SCIP_CALL( branchPseudo(scip, conshdlr, result) );
7908 #endif
7909    }
7910 
7911    return SCIP_OKAY;
7912 }
7913 
7914 
7915 /** feasibility check method of constraint handler for integral solutions */
7916 static
SCIP_DECL_CONSCHECK(consCheckSetppc)7917 SCIP_DECL_CONSCHECK(consCheckSetppc)
7918 {  /*lint --e{715}*/
7919    SCIP_CONS* cons;
7920    SCIP_CONSDATA* consdata;
7921    int c;
7922 
7923    assert(conshdlr != NULL);
7924    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7925    assert(nconss == 0 || conss != NULL);
7926    assert(result != NULL);
7927 
7928    *result = SCIP_FEASIBLE;
7929 
7930    /* check all set partitioning / packing / covering constraints for feasibility */
7931    for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
7932    {
7933       cons = conss[c];
7934       consdata = SCIPconsGetData(cons);
7935       assert(consdata != NULL);
7936       if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
7937       {
7938          if( !checkCons(scip, consdata, sol) )
7939          {
7940             /* constraint is violated */
7941             *result = SCIP_INFEASIBLE;
7942 
7943             if( printreason )
7944             {
7945                SCIP_Real sum = 0.0;
7946                int v;
7947 
7948                SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7949 
7950                for( v = 0; v < consdata->nvars; ++v )
7951                {
7952                   assert(SCIPvarIsBinary(consdata->vars[v]));
7953 
7954                   sum += SCIPgetSolVal(scip, sol, consdata->vars[v]);
7955                }
7956                SCIPinfoMessage(scip, NULL, ";\n");
7957                SCIPinfoMessage(scip, NULL, "violation: the right hand side is violated by by %.15g\n", ABS(sum - 1));
7958             }
7959          }
7960       }
7961    }
7962 
7963    return SCIP_OKAY;
7964 }
7965 
7966 /** domain propagation method of constraint handler */
7967 static
SCIP_DECL_CONSPROP(consPropSetppc)7968 SCIP_DECL_CONSPROP(consPropSetppc)
7969 {  /*lint --e{715}*/
7970    SCIP_Bool cutoff;
7971    SCIP_Bool addcut;
7972    SCIP_Bool mustcheck;
7973    SCIP_Bool inpresolve;
7974    int nfixedvars = 0;
7975    int c;
7976 
7977    assert(conshdlr != NULL);
7978    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7979    assert(nconss == 0 || conss != NULL);
7980    assert(result != NULL);
7981 
7982    *result = SCIP_DIDNOTFIND;
7983 
7984    SCIPdebugMsg(scip, "propagating %d/%d set partitioning / packing / covering constraints\n", nmarkedconss, nconss);
7985 
7986    cutoff = FALSE;
7987    inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
7988 
7989    /* propagate all marked set partitioning / packing / covering constraints */
7990    for( c = nmarkedconss - 1; c >= 0 && !cutoff; --c )
7991    {
7992       assert(SCIPconsGetData(conss[c]) != NULL);
7993 
7994       /* during presolving, we do not want to propagate constraints with multiaggregated variables. After presolving,
7995        * we want to resolve the multiaggregation to have a clean data structure; All initial constraints should not
7996        * have multiaggregated variables, but this is not true for constraints that were introduced during solving
7997        */
7998       if( SCIPconsGetData(conss[c])->existmultaggr )
7999       {
8000          int naddconss, ndelconss;
8001 
8002          if( inpresolve )
8003             continue;
8004 
8005          naddconss = ndelconss = 0;
8006          SCIP_CALL( applyFixings(scip, conss[c], &naddconss, &ndelconss, &nfixedvars, &cutoff) );
8007 
8008          if( cutoff )
8009             break;
8010       }
8011 
8012       /* all multiaggregations should be resolved at here */
8013       assert(inpresolve || ! SCIPconsGetData(conss[c])->existmultaggr);
8014 
8015       SCIP_CALL( processFixings(scip, conss[c], &cutoff, &nfixedvars, &addcut, &mustcheck) );
8016 
8017       SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
8018    }
8019 
8020    /* return the correct result */
8021    if( cutoff )
8022       *result = SCIP_CUTOFF;
8023    else if( nfixedvars > 0 )
8024       *result = SCIP_REDUCEDDOM;
8025 
8026    return SCIP_OKAY; /*lint !e438*/
8027 }
8028 
8029 
8030 /** presolving method of constraint handler */
8031 static
SCIP_DECL_CONSPRESOL(consPresolSetppc)8032 SCIP_DECL_CONSPRESOL(consPresolSetppc)
8033 {  /*lint --e{715}*/
8034    SCIP_CONSHDLRDATA* conshdlrdata;
8035    int oldnfixedvars;
8036    int oldnaggrvars;
8037    int oldndelconss;
8038    int oldnchgcoefs;
8039    int firstchange;
8040    int firstclique;
8041    int lastclique;
8042    int startdelconss;
8043    int c;
8044    SCIP_Bool cutoff;
8045 
8046    assert(conshdlr != NULL);
8047    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8048    assert(scip != NULL);
8049    assert(result != NULL);
8050 
8051    *result = SCIP_DIDNOTFIND;
8052    oldnfixedvars = *nfixedvars;
8053    oldndelconss = *ndelconss;
8054    oldnaggrvars = *naggrvars;
8055    oldnchgcoefs = *nchgcoefs;
8056    cutoff = FALSE;
8057 
8058    conshdlrdata = SCIPconshdlrGetData(conshdlr);
8059    assert(conshdlrdata != NULL);
8060 
8061    /* determine whether we want to run the clique lifting procedure */
8062    conshdlrdata->enablecliquelifting = conshdlrdata->enablecliquelifting || conshdlrdata->updatedsetppctype
8063       || conshdlrdata->noldfixedvars != SCIPgetNFixedVars(scip) || conshdlrdata->noldimpls != SCIPgetNImplications(scip)
8064       || conshdlrdata->noldcliques != SCIPgetNCliques(scip) || conshdlrdata->noldupgrs != nconss;
8065 
8066    /* remember old values */
8067    startdelconss = *ndelconss;
8068    conshdlrdata->noldimpls = SCIPgetNImplications(scip);
8069    conshdlrdata->noldcliques = SCIPgetNCliques(scip);
8070    conshdlrdata->updatedsetppctype = FALSE;
8071 
8072    /* process constraints */
8073    firstchange = INT_MAX;
8074    firstclique = INT_MAX;
8075    lastclique = -1;
8076    for( c = 0; c < nconss && !SCIPisStopped(scip); ++c )
8077    {
8078       SCIP_CONS* cons;
8079       SCIP_CONSDATA* consdata;
8080 
8081       assert(*result != SCIP_CUTOFF);
8082 
8083       cons = conss[c];
8084       assert(cons != NULL);
8085       consdata = SCIPconsGetData(cons);
8086       assert(consdata != NULL);
8087 
8088       /*SCIPdebugMsg(scip, "presolving set partitioning / packing / covering constraint <%s>\n", SCIPconsGetName(cons));*/
8089 
8090       /* remove all variables that are fixed to zero and replace all aggregated variables */
8091       if( consdata->nfixedzeros > 0 || nnewaggrvars > 0 || nnewaddconss > 0 || nnewupgdconss > 0
8092             || *naggrvars > oldnaggrvars || (nrounds == 0 && SCIPgetNRuns(scip) > 1) )
8093       {
8094          SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) );
8095 
8096          if( cutoff )
8097          {
8098             *result = SCIP_CUTOFF;
8099             return SCIP_OKAY;
8100          }
8101 
8102          if( SCIPconsIsDeleted(cons) )
8103             continue;
8104       }
8105 
8106       /* find pairs of negated variables in constraint:
8107        * partitioning/packing: all other variables must be zero, constraint is redundant
8108        * covering: constraint is redundant
8109        *
8110        * find sets of equal variables in constraint:
8111        * partitioning/packing: variable must be zero
8112        * covering: multiple entries of variable can be replaced by single entry
8113        */
8114       SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, &cutoff) );
8115 
8116       if( cutoff )
8117       {
8118          *result = SCIP_CUTOFF;
8119          return SCIP_OKAY;
8120       }
8121 
8122       /* if constraint was deleted while merging, go to the next constraint */
8123       if( !SCIPconsIsActive(cons) )
8124          continue;
8125 
8126       /* remove fixings found by merging */
8127       if( consdata->nfixedzeros > 0 )
8128       {
8129          SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) );
8130 
8131          if( cutoff )
8132          {
8133             *result = SCIP_CUTOFF;
8134             return SCIP_OKAY;
8135          }
8136 
8137          if( SCIPconsIsDeleted(cons) )
8138             continue;
8139       }
8140 
8141       /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
8142        * possible
8143        */
8144       SCIP_CALL( presolvePropagateCons(scip, cons, TRUE, NULL, NULL, NULL, NULL, nfixedvars, naggrvars, ndelconss, &cutoff) );
8145 
8146       if( cutoff )
8147       {
8148          *result = SCIP_CUTOFF;
8149          return SCIP_OKAY;
8150       }
8151 
8152       /* if constraint was deleted while propagation, go to the next constraint */
8153       if( !SCIPconsIsActive(cons) )
8154          continue;
8155 
8156       /* remove fixings found by presolvePropagateCons() */
8157       if( consdata->nfixedzeros > 0 )
8158       {
8159          SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) );
8160 
8161          if( cutoff )
8162          {
8163             *result = SCIP_CUTOFF;
8164             return SCIP_OKAY;
8165          }
8166 
8167          if( SCIPconsIsDeleted(cons) )
8168             continue;
8169       }
8170 
8171       /* perform dual reductions */
8172       if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) )
8173       {
8174          SCIP_CALL( dualPresolving(scip, cons, nfixedvars, ndelconss, result) );
8175 
8176          /* if dual reduction deleted the constraint we take the next */
8177          if( !SCIPconsIsActive(cons) )
8178             continue;
8179       }
8180 
8181       /* remember the first changed constraint to begin the next redundancy round with */
8182       if( firstchange == INT_MAX && consdata->changed )
8183          firstchange = c;
8184 
8185       /* remember the first and last constraints for which we have to add the clique information */
8186       if( !consdata->cliqueadded && consdata->nvars >= 2 )
8187       {
8188          if( firstclique == INT_MAX )
8189             firstclique = c;
8190          lastclique = c;
8191       }
8192    }
8193 
8194    /* update result pointer */
8195    if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss || oldnchgcoefs < *nchgcoefs )
8196       *result = SCIP_SUCCESS;
8197 
8198    if( firstchange < nconss && conshdlrdata->presolusehashing )
8199    {
8200       /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
8201       SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, ndelconss, nchgsides) );
8202       if( oldndelconss < *ndelconss )
8203          *result = SCIP_SUCCESS;
8204    }
8205 
8206    /* determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and
8207     * negated) in any combination of set-partitioning and set-packing constraints
8208     */
8209    if( nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0
8210       && ((conshdlrdata->nsetpart > 0 && !SCIPdoNotMultaggr(scip) && conshdlrdata->conshdlrlinear != NULL)
8211          || (conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip)
8212                && conshdlrdata->nsetpart < nconss && !SCIPdoNotAggr(scip))) )
8213    {
8214       SCIP_CALL( removeDoubleAndSingletonsAndPerformDualpresolve(scip, conss, nconss, conshdlrdata->dualpresolving
8215             && SCIPallowStrongDualReds(scip), conshdlrdata->conshdlrlinear != NULL, nfixedvars,
8216             naggrvars, ndelconss, nchgcoefs, nchgsides, &cutoff) );
8217 
8218       if( cutoff )
8219       {
8220          *result = SCIP_CUTOFF;
8221          return SCIP_OKAY;
8222       }
8223       else if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss )
8224          *result = SCIP_SUCCESS;
8225    }
8226 
8227    /* clique lifting */
8228    if( conshdlrdata->cliquelifting && conshdlrdata->enablecliquelifting && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
8229    {
8230       /* add cliques first before lifting variables */
8231       SCIP_CALL( addCliques(scip, conss, nconss, firstclique, lastclique, naddconss, ndelconss, nchgbds, &cutoff) );
8232 
8233       if( cutoff )
8234       {
8235          *result = SCIP_CUTOFF;
8236          return SCIP_OKAY;
8237       }
8238 
8239       firstclique = nconss;
8240       lastclique = -1;
8241 
8242       /* lift variables and check for fixings due to clique information */
8243       SCIP_CALL( preprocessCliques(scip, conshdlrdata, conss, nconss, nrounds, &firstchange, &firstclique,
8244             &lastclique, nfixedvars, naggrvars, ndelconss, nchgcoefs, &cutoff) );
8245       ++(conshdlrdata->nclqpresolve);
8246 
8247       if( cutoff )
8248       {
8249          *result = SCIP_CUTOFF;
8250          return SCIP_OKAY;
8251       }
8252       else if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss || oldnchgcoefs < *nchgcoefs )
8253          *result = SCIP_SUCCESS;
8254 
8255       /* remember the number of fixings */
8256       conshdlrdata->noldfixedvars = *nfixedvars + *naggrvars;
8257    }
8258 
8259    if( oldndelconss == *ndelconss && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
8260    {
8261       /* check constraints for redundancy */
8262       if( conshdlrdata->presolpairwise )
8263       {
8264          SCIP_Longint npaircomparisons = 0;
8265 
8266          oldndelconss = *ndelconss;
8267          oldnfixedvars = *nfixedvars;
8268 
8269          for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c )
8270          {
8271             assert(*result != SCIP_CUTOFF);
8272 
8273             if( SCIPconsIsActive(conss[c]) && !SCIPconsIsModifiable(conss[c]) )
8274             {
8275                npaircomparisons += (SCIPconsGetData(conss[c])->changed) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange);
8276 
8277                SCIP_CALL( removeRedundantConstraints(scip, conss, firstchange, c, &cutoff, nfixedvars, ndelconss, nchgsides) );
8278                if( cutoff )
8279                {
8280                   *result = SCIP_CUTOFF;
8281                   return SCIP_OKAY;
8282                }
8283 
8284                if( npaircomparisons > NMINCOMPARISONS )
8285                {
8286                   if( (*ndelconss - oldndelconss + *nfixedvars - oldnfixedvars) / ((SCIP_Real)npaircomparisons) < MINGAINPERNMINCOMPARISONS )
8287                      break;
8288                   oldndelconss = *ndelconss;
8289                   oldnfixedvars = *nfixedvars;
8290                   npaircomparisons = 0;
8291                   *result = SCIP_SUCCESS;
8292                }
8293             }
8294          }
8295       }
8296    }
8297 
8298    /* add cliques after lifting variables */
8299    SCIP_CALL( addCliques(scip, conss, nconss, MIN(firstclique, nconss), MIN(lastclique, nconss), naddconss, ndelconss,
8300          nchgbds, &cutoff) );
8301 
8302    if( cutoff )
8303       *result = SCIP_CUTOFF;
8304 
8305    conshdlrdata->enablecliquelifting = FALSE;
8306    conshdlrdata->noldupgrs = nconss - (*ndelconss - startdelconss);
8307 
8308    return SCIP_OKAY;
8309 }
8310 
8311 
8312 /** propagation conflict resolving method of constraint handler */
8313 static
SCIP_DECL_CONSRESPROP(consRespropSetppc)8314 SCIP_DECL_CONSRESPROP(consRespropSetppc)
8315 {  /*lint --e{715}*/
8316    SCIP_CONSDATA* consdata;
8317    int v;
8318 
8319    assert(conshdlr != NULL);
8320    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8321    assert(cons != NULL);
8322    assert(infervar != NULL);
8323    assert(result != NULL);
8324 
8325    consdata = SCIPconsGetData(cons);
8326    assert(consdata != NULL);
8327 
8328    SCIPdebugMsg(scip, "conflict resolving method of set partitioning / packing / covering constraint handler\n");
8329 
8330    if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING
8331       || ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
8332          && SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5) )
8333    {
8334 #ifndef NDEBUG
8335       SCIP_Bool confvarfound;
8336 #endif
8337 
8338       /* the inference constraint is a set partitioning or covering constraint with the inference variable inferred to 1.0:
8339        * the reason for the deduction is the assignment of 0.0 to all other variables
8340        */
8341 #ifndef NDEBUG
8342       confvarfound = FALSE;
8343 #endif
8344       for( v = 0; v < consdata->nvars; ++v )
8345       {
8346          if( consdata->vars[v] != infervar )
8347          {
8348             /* the reason variable must be assigned to zero */
8349             assert(SCIPgetVarUbAtIndex(scip, consdata->vars[v], bdchgidx, FALSE) < 0.5);
8350             SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
8351          }
8352 #ifndef NDEBUG
8353          else
8354          {
8355             assert(!confvarfound);
8356             confvarfound = TRUE;
8357          }
8358 #endif
8359       }
8360       assert(confvarfound);
8361    }
8362    else
8363    {
8364       /* the inference constraint is a set partitioning or packing constraint with the inference variable inferred to 0.0:
8365        * the reason for the deduction is the assignment of 1.0 to a single variable
8366        */
8367       assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < 0.5);
8368 
8369       if( inferinfo >= 0 )
8370       {
8371          assert(SCIPgetVarLbAtIndex(scip, consdata->vars[inferinfo], bdchgidx, FALSE) > 0.5);
8372          SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[inferinfo]) );
8373       }
8374       else
8375       {
8376          for( v = 0; v < consdata->nvars; ++v )
8377          {
8378             if( SCIPgetVarLbAtIndex(scip, consdata->vars[v], bdchgidx, FALSE) > 0.5 )
8379             {
8380                SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
8381                break;
8382             }
8383          }
8384          assert(v < consdata->nvars);
8385       }
8386    }
8387 
8388    *result = SCIP_SUCCESS;
8389 
8390    return SCIP_OKAY;
8391 }
8392 
8393 
8394 /** variable rounding lock method of constraint handler */
8395 static
SCIP_DECL_CONSLOCK(consLockSetppc)8396 SCIP_DECL_CONSLOCK(consLockSetppc)
8397 {  /*lint --e{715}*/
8398    SCIP_CONSDATA* consdata;
8399    int nlocksdown;
8400    int nlocksup;
8401    int i;
8402 
8403    consdata = SCIPconsGetData(cons);
8404    assert(consdata != NULL);
8405 
8406    switch( consdata->setppctype )
8407    {
8408    case SCIP_SETPPCTYPE_PARTITIONING:
8409       nlocksdown = nlockspos + nlocksneg;
8410       nlocksup = nlockspos + nlocksneg;
8411       break;
8412    case SCIP_SETPPCTYPE_PACKING:
8413       nlocksdown = nlocksneg;
8414       nlocksup = nlockspos;
8415       break;
8416    case SCIP_SETPPCTYPE_COVERING:
8417       nlocksdown = nlockspos;
8418       nlocksup = nlocksneg;
8419       break;
8420    default:
8421       SCIPerrorMessage("unknown setppc type\n");
8422       return SCIP_INVALIDDATA;
8423    }
8424 
8425    for( i = 0; i < consdata->nvars; ++i )
8426    {
8427       SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksdown, nlocksup) );
8428    }
8429 
8430    return SCIP_OKAY;
8431 }
8432 
8433 
8434 /** constraint activation notification method of constraint handler */
8435 static
SCIP_DECL_CONSACTIVE(consActiveSetppc)8436 SCIP_DECL_CONSACTIVE(consActiveSetppc)
8437 {  /*lint --e{715}*/
8438    assert(cons != NULL);
8439    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8440    assert(SCIPconsIsTransformed(cons));
8441 
8442    SCIPdebugMsg(scip, "activation information for set partitioning / packing / covering constraint <%s>\n",
8443       SCIPconsGetName(cons));
8444 
8445    /* we only might add the constraint to the propagation list, when we are not activating it in probing mode */
8446    if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMING )
8447    {
8448       SCIP_CONSDATA* consdata = SCIPconsGetData(cons);
8449       assert(consdata != NULL);
8450 
8451       if( consdata->nfixedones >= 1 || consdata->nfixedzeros >= consdata->nvars - 1 )
8452       {
8453          SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
8454       }
8455    }
8456 
8457 #ifdef VARUSES
8458    /* increase the number of uses for each variable in the constraint */
8459    SCIP_CALL( consdataIncVaruses(scip, SCIPconshdlrGetData(conshdlr), SCIPconsGetData(cons)) );
8460 #endif
8461 
8462    return SCIP_OKAY;
8463 }
8464 
8465 
8466 /** constraint deactivation notification method of constraint handler */
8467 static
SCIP_DECL_CONSDEACTIVE(consDeactiveSetppc)8468 SCIP_DECL_CONSDEACTIVE(consDeactiveSetppc)
8469 {  /*lint --e{715}*/
8470    assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8471    assert(SCIPconsIsTransformed(cons));
8472 
8473    SCIPdebugMsg(scip, "deactivation information for set partitioning / packing / covering constraint <%s>\n",
8474       SCIPconsGetName(cons));
8475 
8476 #ifdef VARUSES
8477    /* decrease the number of uses for each variable in the constraint */
8478    SCIP_CALL( consdataDecVaruses(scip, SCIPconshdlrGetData(conshdlr), SCIPconsGetData(cons)) );
8479 #endif
8480 
8481    if( SCIPconsIsDeleted(cons) )
8482    {
8483       SCIP_CONSHDLRDATA* conshdlrdata;
8484       SCIP_CONSDATA* consdata;
8485 
8486       /* get constraint data */
8487       consdata = SCIPconsGetData(cons);
8488       assert(consdata != NULL);
8489 
8490       /* get event handler */
8491       conshdlrdata = SCIPconshdlrGetData(conshdlr);
8492       assert(conshdlrdata != NULL);
8493       assert(conshdlrdata->eventhdlr != NULL);
8494 
8495       /* if constraint belongs to transformed problem space, drop bound change events on variables */
8496       if( consdata->nvars > 0 && SCIPvarIsTransformed(consdata->vars[0]) )
8497       {
8498          SCIP_CALL( dropAllEvents(scip, cons, conshdlrdata->eventhdlr) );
8499       }
8500    }
8501 
8502    return SCIP_OKAY;
8503 }
8504 
8505 /** variable deletion method of constraint handler */
8506 static
SCIP_DECL_CONSDELVARS(consDelvarsSetppc)8507 SCIP_DECL_CONSDELVARS(consDelvarsSetppc)
8508 {
8509    assert( scip != NULL );
8510    assert( conshdlr != NULL );
8511    assert( conss != NULL || nconss == 0 );
8512 
8513    if( nconss > 0 )
8514    {
8515       SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
8516    }
8517 
8518    return SCIP_OKAY;
8519 }
8520 
8521 
8522 
8523 /** constraint display method of constraint handler */
8524 static
SCIP_DECL_CONSPRINT(consPrintSetppc)8525 SCIP_DECL_CONSPRINT(consPrintSetppc)
8526 {  /*lint --e{715}*/
8527    assert( scip != NULL );
8528    assert( conshdlr != NULL );
8529    assert( cons != NULL );
8530 
8531    SCIP_CALL( consdataPrint(scip, SCIPconsGetData(cons), file) );
8532 
8533    return SCIP_OKAY;
8534 }
8535 
8536 /** constraint copying method of constraint handler */
8537 static
SCIP_DECL_CONSCOPY(consCopySetppc)8538 SCIP_DECL_CONSCOPY(consCopySetppc)
8539 {  /*lint --e{715}*/
8540    SCIP_VAR** sourcevars;
8541    const char* consname;
8542    SCIP_Real lhs;
8543    SCIP_Real rhs;
8544    int nvars;
8545    SCIP_SETPPCTYPE type;
8546 
8547    /* get variables and coefficients of the source constraint */
8548    sourcevars = SCIPgetVarsSetppc(sourcescip, sourcecons);
8549    nvars = SCIPgetNVarsSetppc(sourcescip, sourcecons);
8550 
8551    /* get setppc type */
8552    type = SCIPgetTypeSetppc(sourcescip, sourcecons);
8553    lhs = -SCIPinfinity(scip);
8554    rhs = SCIPinfinity(scip);
8555 
8556    switch( type )
8557    {
8558    case SCIP_SETPPCTYPE_PARTITIONING:
8559       lhs = 1.0;
8560       rhs = 1.0;
8561       break;
8562    case SCIP_SETPPCTYPE_PACKING:
8563       rhs = 1.0;
8564       break;
8565    case SCIP_SETPPCTYPE_COVERING:
8566       lhs = 1.0;
8567       break;
8568    default:
8569       SCIPerrorMessage("unknown setppc type\n");
8570       return SCIP_INVALIDDATA;
8571    }
8572 
8573    if( name != NULL )
8574       consname = name;
8575    else
8576       consname = SCIPconsGetName(sourcecons);
8577 
8578    /* copy the logic using the linear constraint copy method */
8579    SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, NULL,
8580          lhs, rhs, varmap, consmap,
8581          initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
8582    assert(cons != NULL);
8583 
8584    return SCIP_OKAY;
8585 }
8586 
8587 /** constraint parsing method of constraint handler */
8588 static
SCIP_DECL_CONSPARSE(consParseSetppc)8589 SCIP_DECL_CONSPARSE(consParseSetppc)
8590 {  /*lint --e{715}*/
8591    SCIP_VAR** vars;
8592    int nvars;
8593 
8594    assert(scip != NULL);
8595    assert(success != NULL);
8596    assert(str != NULL);
8597    assert(name != NULL);
8598    assert(cons != NULL);
8599 
8600    *success = TRUE;
8601 
8602    nvars = 0;
8603    vars = NULL;
8604 
8605    /* check if lhs is just 0 */
8606    if( str[0] == '0' )
8607    {
8608       assert(str[1] == ' ');
8609       str += 2;
8610    }
8611    else
8612    {
8613       SCIP_Real* coefs;
8614       char* endptr;
8615       int coefssize;
8616       int requsize;
8617 
8618       /* initialize buffers for storing the coefficients */
8619       coefssize = 100;
8620       SCIP_CALL( SCIPallocBufferArray(scip, &vars,  coefssize) );
8621       SCIP_CALL( SCIPallocBufferArray(scip, &coefs, coefssize) );
8622 
8623       /* parse linear sum to get variables and coefficients */
8624       SCIP_CALL( SCIPparseVarsLinearsum(scip, str, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) );
8625 
8626       if( *success && requsize > coefssize )
8627       {
8628          /* realloc buffers and try again */
8629          coefssize = requsize;
8630          SCIP_CALL( SCIPreallocBufferArray(scip, &vars,  coefssize) );
8631          SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, coefssize) );
8632 
8633          SCIP_CALL( SCIPparseVarsLinearsum(scip, str, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) );
8634          assert(!*success || requsize <= coefssize); /* if successful, then should have had enough space now */
8635       }
8636 
8637       if( !*success )
8638       {
8639          SCIPerrorMessage("no luck in parsing linear sum '%s'\n", str);
8640       }
8641       else
8642          str = endptr;
8643 
8644       /* free coefficient array */
8645       SCIPfreeBufferArray(scip, &coefs);
8646    }
8647 
8648    /* remove white spaces */
8649    while( isspace((unsigned char)*str) )
8650       str++;
8651 
8652    if( *success )
8653    {
8654       switch( *str )
8655       {
8656          case '=' :
8657             SCIP_CALL( SCIPcreateConsSetpart(scip, cons, name, nvars, vars,
8658                   initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8659             break;
8660          case '<' :
8661             SCIP_CALL( SCIPcreateConsSetpack(scip, cons, name, nvars, vars,
8662                   initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8663             break;
8664          case '>' :
8665             SCIP_CALL( SCIPcreateConsSetcover(scip, cons, name, nvars, vars,
8666                   initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8667             break;
8668          default:
8669             SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing setppc type\n");
8670             *success = FALSE;
8671             break;
8672       }
8673    }
8674 
8675    /* free variable array */
8676    SCIPfreeBufferArrayNull(scip, &vars);
8677 
8678    return SCIP_OKAY;
8679 }
8680 
8681 /** constraint method of constraint handler which returns the variables (if possible) */
8682 static
SCIP_DECL_CONSGETVARS(consGetVarsSetppc)8683 SCIP_DECL_CONSGETVARS(consGetVarsSetppc)
8684 {  /*lint --e{715}*/
8685    SCIP_CONSDATA* consdata;
8686 
8687    consdata = SCIPconsGetData(cons);
8688    assert(consdata != NULL);
8689 
8690    if( varssize < consdata->nvars )
8691       (*success) = FALSE;
8692    else
8693    {
8694       assert(vars != NULL);
8695 
8696       BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
8697       (*success) = TRUE;
8698    }
8699 
8700    return SCIP_OKAY;
8701 }
8702 
8703 /** constraint method of constraint handler which returns the number of variables (if possible) */
8704 static
SCIP_DECL_CONSGETNVARS(consGetNVarsSetppc)8705 SCIP_DECL_CONSGETNVARS(consGetNVarsSetppc)
8706 {  /*lint --e{715}*/
8707    SCIP_CONSDATA* consdata;
8708 
8709    consdata = SCIPconsGetData(cons);
8710    assert(consdata != NULL);
8711 
8712    (*nvars) = consdata->nvars;
8713    (*success) = TRUE;
8714 
8715    return SCIP_OKAY;
8716 }
8717 
8718 /*
8719  * Callback methods of event handler
8720  */
8721 
8722 static
SCIP_DECL_EVENTEXEC(eventExecSetppc)8723 SCIP_DECL_EVENTEXEC(eventExecSetppc)
8724 {  /*lint --e{715}*/
8725    SCIP_CONS* cons;
8726    SCIP_CONSDATA* consdata;
8727    SCIP_EVENTTYPE eventtype;
8728 
8729    assert(eventhdlr != NULL);
8730    assert(eventdata != NULL);
8731    assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
8732    assert(event != NULL);
8733 
8734    /*debugMsg(scip, "Exec method of bound change event handler for set partitioning / packing / covering constraints\n");*/
8735 
8736    cons = (SCIP_CONS*)eventdata;
8737    assert(cons != NULL);
8738 
8739    consdata = SCIPconsGetData(cons);
8740    assert(consdata != NULL);
8741 
8742    eventtype = SCIPeventGetType(event);
8743 
8744    switch( eventtype )
8745    {
8746    case SCIP_EVENTTYPE_LBTIGHTENED:
8747       consdata->nfixedones++;
8748       break;
8749    case SCIP_EVENTTYPE_LBRELAXED:
8750       consdata->nfixedones--;
8751       break;
8752    case SCIP_EVENTTYPE_UBTIGHTENED:
8753       consdata->nfixedzeros++;
8754       break;
8755    case SCIP_EVENTTYPE_UBRELAXED:
8756       consdata->nfixedzeros--;
8757       break;
8758    case SCIP_EVENTTYPE_VARDELETED:
8759       consdata->varsdeleted = TRUE;
8760       break;
8761    case SCIP_EVENTTYPE_VARFIXED:
8762       if( consdata->merged )
8763       {
8764 	 SCIP_VAR* var = SCIPeventGetVar(event);
8765 
8766 	 /* this event should only arise during the presolving stage */
8767 	 assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
8768 	 assert(var != NULL);
8769 
8770 	 /* one variable was changed to a negated or aggregated variable, so maybe we can merge again */
8771 	 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED && SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 )
8772 	    consdata->merged = FALSE;
8773       }
8774 
8775       if( !consdata->existmultaggr )
8776       {
8777 	 SCIP_VAR* var = SCIPeventGetVar(event);
8778 	 assert(var != NULL);
8779 
8780          if( SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
8781             consdata->existmultaggr = TRUE;
8782       }
8783       break;
8784    default:
8785       SCIPerrorMessage("invalid event type\n");
8786       return SCIP_INVALIDDATA;
8787    }
8788    assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
8789    assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
8790 
8791    if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
8792    {
8793       if( consdata->nfixedones >= 1 || consdata->nfixedzeros >= consdata->nvars - 1 )
8794       {
8795          consdata->presolpropagated = FALSE;
8796          SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
8797       }
8798       else if( (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE) && (consdata->nfixedzeros >= consdata->nvars - 2) )
8799       {
8800          consdata->presolpropagated = FALSE;
8801       }
8802    }
8803 
8804    /*debugMsg(scip, " -> constraint has %d zero-fixed and %d one-fixed of %d variables\n",
8805      consdata->nfixedzeros, consdata->nfixedones, consdata->nvars);*/
8806 
8807    return SCIP_OKAY;
8808 }
8809 
8810 
8811 
8812 
8813 /*
8814  * Callback methods of conflict handler
8815  */
8816 
8817 /** conflict processing method of conflict handler (called when conflict was found) */
8818 static
SCIP_DECL_CONFLICTEXEC(conflictExecSetppc)8819 SCIP_DECL_CONFLICTEXEC(conflictExecSetppc)
8820 {  /*lint --e{715}*/
8821    SCIP_VAR** vars;
8822    int i;
8823 
8824    assert(conflicthdlr != NULL);
8825    assert(strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0);
8826    assert(bdchginfos != NULL || nbdchginfos == 0);
8827    assert(result != NULL);
8828 
8829    /* don't process already resolved conflicts */
8830    if( resolved )
8831    {
8832       *result = SCIP_DIDNOTRUN;
8833       return SCIP_OKAY;
8834    }
8835 
8836    *result = SCIP_DIDNOTFIND;
8837 
8838    /* for two (binary) variables we will create a set packing constraint and add the clique information of the conflict is global */
8839    if( nbdchginfos == 2 )
8840    {
8841       SCIP_CONS* cons;
8842       char consname[SCIP_MAXSTRLEN];
8843       SCIP_VAR* twovars[2];
8844 
8845       assert(bdchginfos != NULL);
8846 
8847       twovars[0] = SCIPbdchginfoGetVar(bdchginfos[0]);
8848 
8849       /* we can only treat binary variables */
8850       if( !SCIPvarIsBinary(twovars[0]) )
8851          return SCIP_OKAY;
8852 
8853       /* if the variable is fixed to zero in the conflict set, we have to use its negation */
8854       if( SCIPbdchginfoGetNewbound(bdchginfos[0]) < 0.5 )
8855       {
8856          SCIP_CALL( SCIPgetNegatedVar(scip, twovars[0], &twovars[0]) );
8857       }
8858 
8859       twovars[1] = SCIPbdchginfoGetVar(bdchginfos[1]);
8860 
8861       /* we can only treat binary variables */
8862       if( !SCIPvarIsBinary(twovars[1]) )
8863          return SCIP_OKAY;
8864 
8865       /* if the variable is fixed to zero in the conflict set, we have to use its negation */
8866       if( SCIPbdchginfoGetNewbound(bdchginfos[1]) < 0.5 )
8867       {
8868          SCIP_CALL( SCIPgetNegatedVar(scip, twovars[1], &twovars[1]) );
8869       }
8870 
8871       /* create a constraint out of the conflict set */
8872       (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip));
8873       SCIP_CALL( SCIPcreateConsSetpack(scip, &cons, consname, 2, twovars,
8874             FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
8875 
8876       /* if the constraint gets globally added, we also add the clique information */
8877       if( !SCIPconsIsLocal(cons) )
8878       {
8879          SCIP_Bool infeasible;
8880          int ncliquebdchgs;
8881 
8882          SCIP_CALL( SCIPaddClique(scip, twovars, NULL, 2, FALSE, &infeasible, &ncliquebdchgs) );
8883 
8884          SCIPdebugMsg(scip, "new clique of conflict constraint %s led to %d fixings\n", consname, ncliquebdchgs);
8885 
8886          if( infeasible )
8887          {
8888             SCIPdebugMsg(scip, "new clique of conflict constraint %s led to infeasibility\n", consname);
8889          }
8890       }
8891 
8892       /* add conflict to SCIP */
8893       SCIP_CALL( SCIPaddConflict(scip, node, cons, validnode, conftype, cutoffinvolved) );
8894 
8895       *result = SCIP_CONSADDED;
8896 
8897       return SCIP_OKAY;
8898    }
8899 
8900    /* create array of variables in conflict constraint */
8901    SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
8902    for( i = 0; i < nbdchginfos; ++i )
8903    {
8904       assert(bdchginfos != NULL);
8905 
8906       vars[i] = SCIPbdchginfoGetVar(bdchginfos[i]);
8907 
8908       /* we can only treat binary variables */
8909       if( !SCIPvarIsBinary(vars[i]) )
8910          break;
8911 
8912       /* if the variable is fixed to one in the conflict set, we have to use its negation */
8913       if( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 )
8914       {
8915          SCIP_CALL( SCIPgetNegatedVar(scip, vars[i], &vars[i]) );
8916       }
8917    }
8918 
8919    if( i == nbdchginfos )
8920    {
8921       SCIP_CONS* cons;
8922       char consname[SCIP_MAXSTRLEN];
8923 
8924       /* create a constraint out of the conflict set */
8925       (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip));
8926       SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, consname, nbdchginfos, vars,
8927             FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
8928       SCIP_CALL( SCIPaddConsNode(scip, node, cons, validnode) );
8929       SCIP_CALL( SCIPreleaseCons(scip, &cons) );
8930 
8931       *result = SCIP_CONSADDED;
8932    }
8933 
8934    /* free temporary memory */
8935    SCIPfreeBufferArray(scip, &vars);
8936 
8937    return SCIP_OKAY;
8938 }
8939 
8940 
8941 
8942 
8943 /*
8944  * constraint specific interface methods
8945  */
8946 
8947 /** creates the handler for set partitioning / packing / covering constraints and includes it in SCIP */
SCIPincludeConshdlrSetppc(SCIP * scip)8948 SCIP_RETCODE SCIPincludeConshdlrSetppc(
8949    SCIP*                 scip                /**< SCIP data structure */
8950    )
8951 {
8952    SCIP_CONSHDLRDATA* conshdlrdata;
8953    SCIP_CONSHDLR* conshdlr;
8954    SCIP_EVENTHDLR* eventhdlr;
8955 
8956    /* create event handler for bound change events */
8957    SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
8958          eventExecSetppc, NULL) );
8959 
8960    /* create conflict handler for setppc constraints */
8961    SCIP_CALL( SCIPincludeConflicthdlrBasic(scip, NULL, CONFLICTHDLR_NAME, CONFLICTHDLR_DESC, CONFLICTHDLR_PRIORITY,
8962          conflictExecSetppc, NULL) );
8963 
8964    /* create constraint handler data */
8965    SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
8966 
8967    /* include constraint handler */
8968    SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
8969          CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
8970          consEnfolpSetppc, consEnfopsSetppc, consCheckSetppc, consLockSetppc,
8971          conshdlrdata) );
8972    assert(conshdlr != NULL);
8973 
8974    /* set non-fundamental callbacks via specific setter functions */
8975    SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveSetppc) );
8976    SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveSetppc) );
8977    SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySetppc, consCopySetppc) );
8978    SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSetppc) );
8979    SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsSetppc) );
8980    SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSetppc) );
8981    SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSetppc) );
8982    SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSetppc) );
8983    SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSetppc) );
8984    SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSetppc) );
8985    SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitSetppc) );
8986    SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSetppc) );
8987    SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSetppc) );
8988    SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSetppc, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
8989    SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSetppc) );
8990    SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSetppc, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
8991          CONSHDLR_PROP_TIMING) );
8992    SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSetppc) );
8993    SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSetppc, consSepasolSetppc, CONSHDLR_SEPAFREQ,
8994          CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
8995    SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSetppc) );
8996    SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSetppc) );
8997 
8998    conshdlrdata->conshdlrlinear = SCIPfindConshdlr(scip,"linear");
8999 
9000    if( conshdlrdata->conshdlrlinear != NULL )
9001    {
9002       /* include the linear constraint to setppc constraint upgrade in the linear constraint handler */
9003       SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdSetppc, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) );
9004    }
9005    if( SCIPfindConshdlr(scip, "quadratic") != NULL )
9006    {
9007       /* notify function that upgrades quadratic constraint to setpacking */
9008       SCIP_CALL( SCIPincludeQuadconsUpgrade(scip, quadraticUpgdSetppc, QUADCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
9009    }
9010 
9011    /* set partitioning constraint handler parameters */
9012    SCIP_CALL( SCIPaddIntParam(scip,
9013          "constraints/" CONSHDLR_NAME "/npseudobranches",
9014          "number of children created in pseudo branching (0: disable pseudo branching)",
9015          &conshdlrdata->npseudobranches, TRUE, DEFAULT_NPSEUDOBRANCHES, 0, INT_MAX, NULL, NULL) );
9016    SCIP_CALL( SCIPaddBoolParam(scip,
9017          "constraints/" CONSHDLR_NAME "/presolpairwise",
9018          "should pairwise constraint comparison be performed in presolving?",
9019          &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
9020    SCIP_CALL( SCIPaddBoolParam(scip,
9021          "constraints/" CONSHDLR_NAME "/presolusehashing",
9022          "should hash table be used for detecting redundant constraints in advance",
9023          &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
9024    SCIP_CALL( SCIPaddBoolParam(scip,
9025          "constraints/" CONSHDLR_NAME "/dualpresolving",
9026          "should dual presolving steps be performed?",
9027          &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
9028    SCIP_CALL( SCIPaddBoolParam(scip,
9029          "constraints/" CONSHDLR_NAME "/cliquelifting",
9030          " should we try to lift variables into other clique constraints, fix variables, aggregate them, and also shrink the amount of variables in clique constraints",
9031          &conshdlrdata->cliquelifting, TRUE, DEFAULT_CLIQUELIFTING, NULL, NULL) );
9032    SCIP_CALL( SCIPaddBoolParam(scip,
9033          "constraints/" CONSHDLR_NAME "/addvariablesascliques",
9034          "should we try to generate extra cliques out of all binary variables to maybe fasten redundant constraint detection",
9035          &conshdlrdata->addvariablesascliques, TRUE, DEFAULT_ADDVARIABLESASCLIQUES, NULL, NULL) );
9036    SCIP_CALL( SCIPaddBoolParam(scip,
9037          "constraints/" CONSHDLR_NAME "/cliqueshrinking",
9038          "should we try to shrink the number of variables in a clique constraints, by replacing more than one variable by only one",
9039          &conshdlrdata->cliqueshrinking, TRUE, DEFAULT_CLIQUESHRINKING, NULL, NULL) );
9040 
9041    return SCIP_OKAY;
9042 }
9043 
9044 /** creates and captures a set partitioning constraint
9045  *
9046  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9047  */
SCIPcreateConsSetpart(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Bool initial,SCIP_Bool separate,SCIP_Bool enforce,SCIP_Bool check,SCIP_Bool propagate,SCIP_Bool local,SCIP_Bool modifiable,SCIP_Bool dynamic,SCIP_Bool removable,SCIP_Bool stickingatnode)9048 SCIP_RETCODE SCIPcreateConsSetpart(
9049    SCIP*                 scip,               /**< SCIP data structure */
9050    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
9051    const char*           name,               /**< name of constraint */
9052    int                   nvars,              /**< number of variables in the constraint */
9053    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
9054    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
9055                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9056    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
9057                                               *   Usually set to TRUE. */
9058    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
9059                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9060    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
9061                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9062    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
9063                                               *   Usually set to TRUE. */
9064    SCIP_Bool             local,              /**< is constraint only valid locally?
9065                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9066    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
9067                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
9068                                               *   adds coefficients to this constraint. */
9069    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
9070                                               *   Usually set to FALSE. Set to TRUE for own cuts which
9071                                               *   are separated as constraints. */
9072    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
9073                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9074    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
9075                                               *   if it may be moved to a more global node?
9076                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9077    )
9078 {
9079    return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_PARTITIONING,
9080       initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode);
9081 }
9082 
9083 /** creates and captures a set partitioning constraint with all constraint flags set
9084  *  to their default values
9085  *
9086  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9087  */
SCIPcreateConsBasicSetpart(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars)9088 SCIP_RETCODE SCIPcreateConsBasicSetpart(
9089    SCIP*                 scip,               /**< SCIP data structure */
9090    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
9091    const char*           name,               /**< name of constraint */
9092    int                   nvars,              /**< number of variables in the constraint */
9093    SCIP_VAR**            vars                /**< array with variables of constraint entries */
9094    )
9095 {
9096    SCIP_CALL( SCIPcreateConsSetpart(scip, cons, name, nvars, vars,
9097          TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9098 
9099    return SCIP_OKAY;
9100 }
9101 
9102 /** creates and captures a set packing constraint
9103  *
9104  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9105  */
SCIPcreateConsSetpack(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Bool initial,SCIP_Bool separate,SCIP_Bool enforce,SCIP_Bool check,SCIP_Bool propagate,SCIP_Bool local,SCIP_Bool modifiable,SCIP_Bool dynamic,SCIP_Bool removable,SCIP_Bool stickingatnode)9106 SCIP_RETCODE SCIPcreateConsSetpack(
9107    SCIP*                 scip,               /**< SCIP data structure */
9108    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
9109    const char*           name,               /**< name of constraint */
9110    int                   nvars,              /**< number of variables in the constraint */
9111    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
9112    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
9113                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9114    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
9115                                               *   Usually set to TRUE. */
9116    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
9117                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9118    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
9119                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9120    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
9121                                               *   Usually set to TRUE. */
9122    SCIP_Bool             local,              /**< is constraint only valid locally?
9123                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9124    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
9125                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
9126                                               *   adds coefficients to this constraint. */
9127    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
9128                                               *   Usually set to FALSE. Set to TRUE for own cuts which
9129                                               *   are separated as constraints. */
9130    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
9131                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9132    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
9133                                               *   if it may be moved to a more global node?
9134                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9135    )
9136 {
9137    return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_PACKING,
9138       initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode);
9139 }
9140 
9141 /** creates and captures a set packing constraint with all constraint flags set
9142  *  to their default values
9143  *
9144  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9145  */
SCIPcreateConsBasicSetpack(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars)9146 SCIP_RETCODE SCIPcreateConsBasicSetpack(
9147    SCIP*                 scip,               /**< SCIP data structure */
9148    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
9149    const char*           name,               /**< name of constraint */
9150    int                   nvars,              /**< number of variables in the constraint */
9151    SCIP_VAR**            vars                /**< array with variables of constraint entries */
9152    )
9153 {
9154    SCIP_CALL( SCIPcreateConsSetpack(scip, cons, name, nvars, vars,
9155          TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9156 
9157    return SCIP_OKAY;
9158 }
9159 
9160 /** creates and captures a set covering constraint
9161  *
9162  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9163  */
SCIPcreateConsSetcover(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Bool initial,SCIP_Bool separate,SCIP_Bool enforce,SCIP_Bool check,SCIP_Bool propagate,SCIP_Bool local,SCIP_Bool modifiable,SCIP_Bool dynamic,SCIP_Bool removable,SCIP_Bool stickingatnode)9164 SCIP_RETCODE SCIPcreateConsSetcover(
9165    SCIP*                 scip,               /**< SCIP data structure */
9166    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
9167    const char*           name,               /**< name of constraint */
9168    int                   nvars,              /**< number of variables in the constraint */
9169    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
9170    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
9171                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9172    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
9173                                               *   Usually set to TRUE. */
9174    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
9175                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9176    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
9177                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9178    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
9179                                               *   Usually set to TRUE. */
9180    SCIP_Bool             local,              /**< is constraint only valid locally?
9181                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9182    SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
9183                                               *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
9184                                               *   adds coefficients to this constraint. */
9185    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
9186                                               *   Usually set to FALSE. Set to TRUE for own cuts which
9187                                               *   are separated as constraints. */
9188    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
9189                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9190    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
9191                                               *   if it may be moved to a more global node?
9192                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9193    )
9194 {
9195    return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_COVERING,
9196       initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode);
9197 }
9198 
9199 /** creates and captures a set covering constraint with all constraint flags set
9200  *  to their default values
9201  *
9202  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9203  */
SCIPcreateConsBasicSetcover(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars)9204 SCIP_RETCODE SCIPcreateConsBasicSetcover(
9205    SCIP*                 scip,               /**< SCIP data structure */
9206    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
9207    const char*           name,               /**< name of constraint */
9208    int                   nvars,              /**< number of variables in the constraint */
9209    SCIP_VAR**            vars                /**< array with variables of constraint entries */
9210    )
9211 {
9212    SCIP_CALL( SCIPcreateConsSetcover(scip, cons, name, nvars, vars,
9213          TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9214 
9215    return SCIP_OKAY;
9216 }
9217 
9218 /** adds coefficient in set partitioning / packing / covering constraint */
SCIPaddCoefSetppc(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)9219 SCIP_RETCODE SCIPaddCoefSetppc(
9220    SCIP*                 scip,               /**< SCIP data structure */
9221    SCIP_CONS*            cons,               /**< constraint data */
9222    SCIP_VAR*             var                 /**< variable to add to the constraint */
9223    )
9224 {
9225    assert(var != NULL);
9226 
9227    /*debugMsg(scip, "adding variable <%s> to setppc constraint <%s>\n",
9228      SCIPvarGetName(var), SCIPconsGetName(cons));*/
9229 
9230    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9231    {
9232       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9233       return SCIP_INVALIDDATA;
9234    }
9235 
9236    SCIP_CALL( addCoef(scip, cons, var) );
9237 
9238    return SCIP_OKAY;
9239 }
9240 
9241 /** gets number of variables in set partitioning / packing / covering constraint */
SCIPgetNVarsSetppc(SCIP * scip,SCIP_CONS * cons)9242 int SCIPgetNVarsSetppc(
9243    SCIP*                 scip,               /**< SCIP data structure */
9244    SCIP_CONS*            cons                /**< constraint data */
9245    )
9246 {
9247    SCIP_CONSDATA* consdata;
9248 
9249    assert(scip != NULL);
9250 
9251    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9252    {
9253       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9254       SCIPABORT();
9255       return -1;  /*lint !e527*/
9256    }
9257 
9258    consdata = SCIPconsGetData(cons);
9259    assert(consdata != NULL);
9260 
9261    return consdata->nvars;
9262 }
9263 
9264 /** gets array of variables in set partitioning / packing / covering constraint */
SCIPgetVarsSetppc(SCIP * scip,SCIP_CONS * cons)9265 SCIP_VAR** SCIPgetVarsSetppc(
9266    SCIP*                 scip,               /**< SCIP data structure */
9267    SCIP_CONS*            cons                /**< constraint data */
9268    )
9269 {
9270    SCIP_CONSDATA* consdata;
9271 
9272    assert(scip != NULL);
9273 
9274    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9275    {
9276       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9277       SCIPABORT();
9278       return NULL;  /*lint !e527*/
9279    }
9280 
9281    consdata = SCIPconsGetData(cons);
9282    assert(consdata != NULL);
9283 
9284    return consdata->vars;
9285 }
9286 
9287 /** gets type of set partitioning / packing / covering constraint */
SCIPgetTypeSetppc(SCIP * scip,SCIP_CONS * cons)9288 SCIP_SETPPCTYPE SCIPgetTypeSetppc(
9289    SCIP*                 scip,               /**< SCIP data structure */
9290    SCIP_CONS*            cons                /**< constraint data */
9291    )
9292 {
9293    SCIP_CONSDATA* consdata;
9294 
9295    assert(scip != NULL);
9296 
9297    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9298    {
9299       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9300       SCIPABORT();
9301    }
9302 
9303    consdata = SCIPconsGetData(cons);
9304    assert(consdata != NULL);
9305 
9306    return (SCIP_SETPPCTYPE)(consdata->setppctype);
9307 }
9308 
9309 /** gets the dual solution of the set partitioning / packing / covering constraint in the current LP */
SCIPgetDualsolSetppc(SCIP * scip,SCIP_CONS * cons)9310 SCIP_Real SCIPgetDualsolSetppc(
9311    SCIP*                 scip,               /**< SCIP data structure */
9312    SCIP_CONS*            cons                /**< constraint data */
9313    )
9314 {
9315    SCIP_CONSDATA* consdata;
9316 
9317    assert(scip != NULL);
9318 
9319    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9320    {
9321       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9322       SCIPABORT();
9323       return SCIP_INVALID;  /*lint !e527*/
9324    }
9325 
9326    consdata = SCIPconsGetData(cons);
9327    assert(consdata != NULL);
9328 
9329    if( consdata->row != NULL )
9330       return SCIProwGetDualsol(consdata->row);
9331    else
9332       return 0.0;
9333 }
9334 
9335 /** gets the dual Farkas value of the set partitioning / packing / covering constraint in the current infeasible LP */
SCIPgetDualfarkasSetppc(SCIP * scip,SCIP_CONS * cons)9336 SCIP_Real SCIPgetDualfarkasSetppc(
9337    SCIP*                 scip,               /**< SCIP data structure */
9338    SCIP_CONS*            cons                /**< constraint data */
9339    )
9340 {
9341    SCIP_CONSDATA* consdata;
9342 
9343    assert(scip != NULL);
9344 
9345    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9346    {
9347       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9348       SCIPABORT();
9349       return SCIP_INVALID;  /*lint !e527*/
9350    }
9351 
9352    consdata = SCIPconsGetData(cons);
9353    assert(consdata != NULL);
9354 
9355    if( consdata->row != NULL )
9356       return SCIProwGetDualfarkas(consdata->row);
9357    else
9358       return 0.0;
9359 }
9360 
9361 /** returns the linear relaxation of the given set partitioning / packing / covering constraint; may return NULL if no
9362  *  LP row was yet created; the user must not modify the row!
9363  */
SCIPgetRowSetppc(SCIP * scip,SCIP_CONS * cons)9364 SCIP_ROW* SCIPgetRowSetppc(
9365    SCIP*                 scip,               /**< SCIP data structure */
9366    SCIP_CONS*            cons                /**< constraint data */
9367    )
9368 {
9369    SCIP_CONSDATA* consdata;
9370 
9371    assert(scip != NULL);
9372 
9373    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9374    {
9375       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9376       SCIPABORT();
9377       return NULL;  /*lint !e527*/
9378    }
9379 
9380    consdata = SCIPconsGetData(cons);
9381    assert(consdata != NULL);
9382 
9383    return consdata->row;
9384 }
9385 
9386 /** returns current number of variables fixed to one in the constraint  */
SCIPgetNFixedonesSetppc(SCIP * scip,SCIP_CONS * cons)9387 int SCIPgetNFixedonesSetppc(
9388    SCIP*                 scip,               /**< SCIP data structure */
9389    SCIP_CONS*            cons                /**< constraint data */
9390    )
9391 {
9392    SCIP_CONSDATA* consdata;
9393 
9394    assert(scip != NULL);
9395 
9396    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9397    {
9398       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9399       SCIPABORT();
9400       return -1;  /*lint !e527*/
9401    }
9402 
9403    consdata = SCIPconsGetData(cons);
9404    assert(consdata != NULL);
9405 
9406    return consdata->nfixedones;
9407 }
9408 
9409 
9410 /** returns current number of variables fixed to zero in the constraint  */
SCIPgetNFixedzerosSetppc(SCIP * scip,SCIP_CONS * cons)9411 int SCIPgetNFixedzerosSetppc(
9412    SCIP*                 scip,               /**< SCIP data structure */
9413    SCIP_CONS*            cons                /**< constraint data */
9414    )
9415 {
9416    SCIP_CONSDATA* consdata;
9417 
9418    assert(scip != NULL);
9419 
9420    if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9421    {
9422       SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9423       SCIPABORT();
9424       return -1;  /*lint !e527*/
9425    }
9426 
9427    consdata = SCIPconsGetData(cons);
9428    assert(consdata != NULL);
9429 
9430    return consdata->nfixedzeros;
9431 }
9432 
9433 /** cleans up (multi-)aggregations and fixings from setppc constraints */
SCIPcleanupConssSetppc(SCIP * scip,SCIP_Bool onlychecked,SCIP_Bool * infeasible,int * naddconss,int * ndelconss,int * nchgcoefs,int * nfixedvars)9434 SCIP_RETCODE SCIPcleanupConssSetppc(
9435    SCIP*                 scip,               /**< SCIP data structure */
9436    SCIP_Bool             onlychecked,        /**< should only checked constraints be cleaned up? */
9437    SCIP_Bool*            infeasible,         /**< pointer to return whether problem was detected to be infeasible */
9438    int*                  naddconss,          /**< pointer to count number of added (linear) constraints */
9439    int*                  ndelconss,          /**< pointer to count number of deleted (setppc) constraints */
9440    int*                  nchgcoefs,          /**< pointer to count number of changed coefficients */
9441    int*                  nfixedvars          /**< pointer to count number of fixed variables */
9442    )
9443 {
9444    SCIP_CONSHDLR* conshdlr;
9445    SCIP_CONS** conss;
9446    int nconss;
9447    int i;
9448 
9449    conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9450    if( conshdlr == NULL )
9451       return SCIP_OKAY;
9452 
9453    assert(naddconss != NULL);
9454    assert(ndelconss != NULL);
9455    assert(nfixedvars != NULL);
9456    assert(infeasible != NULL);
9457    *infeasible = FALSE;
9458 
9459    nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
9460    conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
9461 
9462    /* loop backwards since then deleted constraints do not interfere with the loop */
9463    for( i = nconss - 1; i > 0; --i )
9464    {
9465       SCIP_CONS* cons = conss[i];
9466 
9467       SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, infeasible) );
9468 
9469       if( *infeasible )
9470          break;
9471 
9472       if( SCIPconsIsDeleted(cons) )
9473          continue;
9474 
9475       /* merging unmerged constraints */
9476       SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, infeasible) );
9477 
9478       if( *infeasible )
9479          break;
9480    }
9481 
9482    return SCIP_OKAY;
9483 }
9484