Scippy

SCIP

Solving Constraint Integer Programs

cons_setppc.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cons_setppc.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief Constraint handler for the set partitioning / packing / covering constraints \f$1^T x\ \{=, \le, \ge\}\ 1\f$.
28  * @author Tobias Achterberg
29  * @author Michael Winkler
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 #include "blockmemshell/memory.h"
35 #include "scip/cons_nonlinear.h"
36 #include "scip/cons_linear.h"
37 #include "scip/cons_setppc.h"
38 #include "scip/pub_conflict.h"
39 #include "scip/pub_cons.h"
40 #include "scip/pub_event.h"
41 #include "scip/pub_lp.h"
42 #include "scip/pub_message.h"
43 #include "scip/pub_misc.h"
44 #include "scip/pub_misc_sort.h"
45 #include "scip/pub_var.h"
46 #include "scip/scip_conflict.h"
47 #include "scip/scip_cons.h"
48 #include "scip/scip_cut.h"
49 #include "scip/scip_event.h"
50 #include "scip/scip_general.h"
51 #include "scip/scip_lp.h"
52 #include "scip/scip_mem.h"
53 #include "scip/scip_message.h"
54 #include "scip/scip_nlp.h"
55 #include "scip/scip_numerics.h"
56 #include "scip/scip_param.h"
57 #include "scip/scip_prob.h"
58 #include "scip/scip_probing.h"
59 #include "scip/scip_randnumgen.h"
60 #include "scip/scip_sol.h"
61 #include "scip/scip_solvingstats.h"
62 #include "scip/scip_var.h"
63 
64 
65 #define CONSHDLR_NAME "setppc"
66 #define CONSHDLR_DESC "set partitioning / packing / covering constraints"
67 #define CONSHDLR_SEPAPRIORITY +700000 /**< priority of the constraint handler for separation */
68 #define CONSHDLR_ENFOPRIORITY -700000 /**< priority of the constraint handler for constraint enforcing */
69 #define CONSHDLR_CHECKPRIORITY -700000 /**< priority of the constraint handler for checking feasibility */
70 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
71 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
72 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
73  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
74 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
75 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
76 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
77 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
78 
79 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
80 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
81 
82 #define LINCONSUPGD_PRIORITY +700000 /**< priority of the constraint handler for upgrading of linear constraints */
83 #define NONLINCONSUPGD_PRIORITY +700000 /**< priority of the constraint handler for upgrading of nonlinear constraints */
84 
85 #define EVENTHDLR_NAME "setppc"
86 #define EVENTHDLR_DESC "bound change event handler for set partitioning / packing / covering constraints"
87 
88 #define CONFLICTHDLR_NAME "setppc"
89 #define CONFLICTHDLR_DESC "conflict handler creating set covering constraints"
90 #define CONFLICTHDLR_PRIORITY LINCONSUPGD_PRIORITY
91 
92 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
93 
94 #define HASHSIZE_SETPPCCONS 500 /**< minimal size of hash table in setppc constraint tables */
95 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
96 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
97 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */
98 
99 #define DEFAULT_RANDSEED 3
101 /*#define VARUSES*/ /* activate variable usage counting, that is necessary for LP and pseudo branching */
102 /*#define BRANCHLP*/ /* BRANCHLP is only useful if the ENFOPRIORITY is set to a positive value */
103 #ifdef BRANCHLP
104 #define MINBRANCHWEIGHT 0.3 /**< minimum weight of both sets in binary set branching */
105 #define MAXBRANCHWEIGHT 0.7 /**< maximum weight of both sets in binary set branching */
106 #endif
107 #define DEFAULT_NPSEUDOBRANCHES 2 /**< number of children created in pseudo branching (0: disable branching) */
108 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
110 #define DEFAULT_CLIQUELIFTING FALSE /**< should we try to lift variables into other clique constraints, fix
111  * variables, aggregate them, and also shrink the amount of variables in
112  * clique constraints
113  */
114 #define DEFAULT_ADDVARIABLESASCLIQUES FALSE/**< should we try to generate extra clique constraint out of all binary
115  * variables to hopefully fasten the detection of redundant clique
116  * constraints */
117 #define DEFAULT_CLIQUESHRINKING TRUE /**< should we try to shrink the number of variables in a clique constraints, by
118  * replacing more than one variable by only one
119  */
120 
121 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
122 
123 /*
124  * Data structures
125  */
126 
127 /** constraint handler data */
128 struct SCIP_ConshdlrData
129 {
130  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
131  SCIP_CONSHDLR* conshdlrlinear; /**< pointer to linear constraint handler or NULL if not included */
132 #ifdef VARUSES
133  SCIP_INTARRAY* varuses; /**< number of times a var is used in the active setppc constraints */
134 #endif
135  SCIP_Longint nsetpart; /**< number of set partitioning constraints in transformed problem */
136  int npseudobranches; /**< number of children created in pseudo branching (0 to disable branching) */
137  int noldfixedvars; /**< number of fixed variables after last clique lifting run */
138  int noldimpls; /**< number of implication before last clique lifting run */
139  int noldcliques; /**< number of cliques before last clique lifting run */
140  int noldupgrs; /**< number of setppc constraints since the last clique lifting run */
141  int nclqpresolve; /**< number of setppc clique lifting runs */
142  SCIP_Bool updatedsetppctype; /**< remember whether we upgraded a constraint type */
143  SCIP_Bool cliquelifting; /**< should we perform the clique lifting procedure */
144  SCIP_Bool enablecliquelifting;/**< check whether we have enough changes to run the lifting procedure again */
145  SCIP_Bool cliqueshrinking; /**< should we try to shrink the number of variables in a clique
146  * constraints, by replacing more than one variable by only one
147  */
148  SCIP_Bool addvariablesascliques;/**< should we try to generate extra clique constraint out of all binary
149  * variables to hopefully fasten the detection of redundant clique
150  * constraints */
151  SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
152  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
153  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
154  SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
155 };
156 
157 /** constraint data for set partitioning / packing / covering constraints */
158 struct SCIP_ConsData
159 {
160  uint64_t signature; /**< bit signature of vars array */
161  SCIP_ROW* row; /**< LP row, if constraint is already stored in LP row format */
162  SCIP_NLROW* nlrow; /**< NLP row, if constraint has been added to NLP relaxation */
163  SCIP_VAR** vars; /**< variables of the constraint */
164  int varssize; /**< size of vars array */
165  int nvars; /**< number of variables in the constraint */
166  int nfixedzeros; /**< current number of variables fixed to zero in the constraint */
167  int nfixedones; /**< current number of variables fixed to one in the constraint */
168  unsigned int setppctype:2; /**< type of constraint: set partitioning, packing or covering */
169  unsigned int sorted:1; /**< are the constraint's variables sorted? */
170  unsigned int cliqueadded:1; /**< was the set partitioning / packing constraint already added as clique? */
171  unsigned int validsignature:1; /**< is the bit signature valid? */
172  unsigned int changed:1; /**< was constraint changed since last redundancy round in preprocessing? */
173  unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
174  unsigned int merged:1; /**< are the constraint's equal/negated variables already merged? */
175  unsigned int presolpropagated:1; /**< was the constraint already propagated in presolving w.r.t. the current domains? */
176  unsigned int existmultaggr:1; /**< does this constraint contain aggregations */
177  unsigned int catchevents:1; /**< are events installed for this constraint? */
178 };
179 
180 
181 
182 
183 /*
184  * Local methods
185  */
186 
187 /** compares two active constraints of type set partitioning or set packing such that a "-1" is return if
188  * 1. the first constraint is a set partitioning constraint and the second is a set packing or
189  * 2. both constraints are set partitioning constraints and the second has more! variables than the first or
190  * 3. both constraints are set packing constraints and the second has less! variables than the first
191  * a "0" is return if
192  * 1. both constraint are of the same type and have the amount of variables or
193  * and a "1" is returned otherwise
194  */
195 static
196 int setppcCompare(
197  SCIP_CONS*const cons1, /**< first problem variable */
198  SCIP_CONS*const cons2 /**< second problem variable */
199  )
200 {
201  SCIP_CONSDATA* consdata1;
202  SCIP_CONSDATA* consdata2;
203 
204  assert(cons1 != NULL);
205  assert(cons2 != NULL);
206  assert(SCIPconsIsActive(cons1));
207  assert(SCIPconsIsActive(cons2));
208 
209  /* the partitioning type should be the smallest value and the packing the second smallest */
210  assert(SCIP_SETPPCTYPE_PARTITIONING < SCIP_SETPPCTYPE_PACKING); /*lint !e506*/
211 
212  consdata1 = SCIPconsGetData(cons1);
213  assert(consdata1 != NULL);
214  assert(consdata1->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
215  consdata2 = SCIPconsGetData(cons2);
216  assert(consdata2 != NULL);
217  assert(consdata2->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
218 
219  if( consdata1->setppctype < consdata2->setppctype ||
220  (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) || /*lint !e641*/
221  (consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars) ) /*lint !e641*/
222  return -1;
223  else if( (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars) ) /*lint !e641*/
224  return 0;
225  else
226  {
227  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*/
228  return +1;
229  }
230 }
231 
232 /** sort constraints first after type (partitioning before packing before covering) and second after number of
233  * variables such that the partitioning constraints have increasing number of variables and the packing constraints
234  * have decreasing number of variables */
235 static
236 SCIP_DECL_SORTPTRCOMP(setppcConssSort)
237 {
238  return setppcCompare((SCIP_CONS*)elem1, (SCIP_CONS*)elem2);
239 }
240 
241 /** compares two setppc constraints such that a "-1" is return if the first constraint is active and
242  * 1. the second constraint is deleted
243  * 2. the first constraint is a set partitioning constraint and the second is a set packing or
244  * 3. both constraints are set partitioning constraints and the second has more! variables than the first or
245  * 4. both constraints are set packing constraints and the second has less! variables than the first
246  * a "0" is return if
247  * 1. both constraint are set-covering constraints
248  * 2. both constraint are of the same type and have the amount of variables or
249  * and a "1" is returned otherwise
250  */
251 static
252 int setppcCompare2(
253  SCIP_CONS*const cons1, /**< first problem variable */
254  SCIP_CONS*const cons2 /**< second problem variable */
255  )
256 {
257  SCIP_CONSDATA* consdata1;
258  SCIP_CONSDATA* consdata2;
259 
260  assert(cons1 != NULL);
261  assert(cons2 != NULL);
262 
263  if( SCIPconsIsDeleted(cons1) )
264  {
265  if( SCIPconsIsDeleted(cons2) )
266  return 0;
267  else
268  return +1;
269  }
270  else if( SCIPconsIsDeleted(cons2) )
271  return -1;
272 
273  consdata1 = SCIPconsGetData(cons1);
274  assert(consdata1 != NULL);
275  consdata2 = SCIPconsGetData(cons2);
276  assert(consdata2 != NULL);
277 
278  /* the partitioning type should be the smallest value and the packing the second smallest */
280 
281  if( consdata1->setppctype < consdata2->setppctype ||
282  ((SCIP_SETPPCTYPE)consdata1->setppctype != SCIP_SETPPCTYPE_COVERING &&
283  (((SCIP_SETPPCTYPE)consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) ||
284  ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars))) )
285  return -1;
286  else if( ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_COVERING || (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars)) )
287  return 0;
288  else
289  {
290  assert(consdata1->setppctype > consdata2->setppctype || ((consdata1->setppctype == consdata2->setppctype) &&
291  ((consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars > consdata2->nvars)
292  || (consdata1->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars < consdata2->nvars)))); /*lint !e641*/
293  return +1;
294  }
295 }
296 
297 /** sort constraints first after type (partitioning before packing before covering) and second after number of
298  * variables such that the partitioning constraints have increasing number of variables and the packing constraints
299  * have decreasing number of variables */
300 static
301 SCIP_DECL_SORTPTRCOMP(setppcConssSort2)
302 {
303  return setppcCompare2((SCIP_CONS*)elem1, (SCIP_CONS*)elem2);
304 }
305 
306 
307 /** installs rounding locks for the given variable in the given setppc constraint */
308 static
310  SCIP* scip, /**< SCIP data structure */
311  SCIP_CONS* cons, /**< setppc constraint */
312  SCIP_VAR* var /**< variable of constraint entry */
313  )
314 {
315  SCIP_CONSDATA* consdata;
316 
317  consdata = SCIPconsGetData(cons);
318  assert(consdata != NULL);
319 
320  switch( consdata->setppctype )
321  {
323  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
324  break;
326  SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
327  break;
329  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, FALSE) );
330  break;
331  default:
332  SCIPerrorMessage("unknown setppc type\n");
333  return SCIP_INVALIDDATA;
334  }
335 
336  return SCIP_OKAY;
337 }
338 
339 /** removes rounding locks for the given variable in the given setppc constraint */
340 static
342  SCIP* scip, /**< SCIP data structure */
343  SCIP_CONS* cons, /**< setppc constraint */
344  SCIP_VAR* var /**< variable of constraint entry */
345  )
346 {
347  SCIP_CONSDATA* consdata;
348 
349  consdata = SCIPconsGetData(cons);
350  assert(consdata != NULL);
351 
352  switch( consdata->setppctype )
353  {
355  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
356  break;
358  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
359  break;
361  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
362  break;
363  default:
364  SCIPerrorMessage("unknown setppc type\n");
365  return SCIP_INVALIDDATA;
366  }
367 
368  return SCIP_OKAY;
369 }
370 
371 /** creates constraint handler data for set partitioning / packing / covering constraint handler */
372 static
374  SCIP* scip, /**< SCIP data structure */
375  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
376  SCIP_EVENTHDLR* eventhdlr /**< event handler */
377  )
378 {
379  assert(scip != NULL);
380  assert(conshdlrdata != NULL);
381  assert(eventhdlr != NULL);
382 
383  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
384 #ifdef VARUSES
385  SCIP_CALL( SCIPcreateIntarray(scip, &(*conshdlrdata)->varuses) );
386 #endif
387  (*conshdlrdata)->npseudobranches = DEFAULT_NPSEUDOBRANCHES;
388 
389  /* set event handler for bound change events */
390  (*conshdlrdata)->eventhdlr = eventhdlr;
391  (*conshdlrdata)->nsetpart = 0;
392 
393  /* create a random number generator */
394  SCIP_CALL( SCIPcreateRandom(scip, &(*conshdlrdata)->randnumgen,
396 
397  return SCIP_OKAY;
398 }
399 
400 /** frees constraint handler data for set partitioning / packing / covering constraint handler */
401 static
403  SCIP* scip, /**< SCIP data structure */
404  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
405  )
406 {
407  assert(conshdlrdata != NULL);
408  assert(*conshdlrdata != NULL);
409 
410 #ifdef VARUSES
411  SCIP_CALL( SCIPfreeIntarray(scip, &(*conshdlrdata)->varuses) );
412 #endif
413 
414  /* free random number generator */
415  SCIPfreeRandom(scip, &(*conshdlrdata)->randnumgen);
416 
417  SCIPfreeBlockMemory(scip, conshdlrdata);
418 
419  return SCIP_OKAY;
420 }
421 
422 #ifdef VARUSES
423 /** adds the given value to the usage counter of the given variable */
424 static
425 SCIP_RETCODE conshdlrdataAddVaruses(
426  SCIP* scip, /**< SCIP data structure */
427  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
428  SCIP_VAR* var, /**< variable to increase usage counter for */
429  int addval /**< value to add to the usage counter */
430  )
431 {
432  SCIP_INTARRAY* varuses;
433 
434  assert(conshdlrdata != NULL);
435  assert(var != NULL);
436 
437  varuses = conshdlrdata->varuses;
438  assert(varuses != NULL);
439 
440  /* if the variable is the negation of a problem variable, count the varuses in the problem variable */
441  if( SCIPvarIsNegated(var) )
442  {
443  SCIP_VAR* negvar;
444  int varindex;
445 
446  /* move the varuses value of the negated variable to the active problem variable */
447  varindex = SCIPvarGetIndex(var);
448  addval += SCIPgetIntarrayVal(scip, varuses, varindex);
449  SCIP_CALL( SCIPsetIntarrayVal(scip, varuses, varindex, 0) );
450  SCIP_CALL( SCIPgetNegatedVar(scip, var, &negvar) );
451  var = negvar;
452  }
453 
454  /* increase varuses counter */
455  SCIP_CALL( SCIPincIntarrayVal(scip, varuses, SCIPvarGetIndex(var), addval) );
456 
457  SCIPdebugMsg(scip, "added %d to varuses of <%s>: %d\n",
458  addval, SCIPvarGetName(var), SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var)));
459 
460  return SCIP_OKAY;
461 }
462 
463 /** increases the usage counter of the given variable */
464 static
465 SCIP_RETCODE conshdlrdataIncVaruses(
466  SCIP* scip, /**< SCIP data structure */
467  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
468  SCIP_VAR* var /**< variable to increase usage counter for */
469  )
470 {
471  assert(conshdlrdata != NULL);
472 
473  SCIPdebugMsg(scip, "increasing varuses of <%s>: %d\n",
474  SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var)));
475 
476  SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, +1) );
477 
478  return SCIP_OKAY;
479 }
480 
481 /** decreases the usage counter of the given variable */
482 static
483 SCIP_RETCODE conshdlrdataDecVaruses(
484  SCIP* scip, /**< SCIP data structure */
485  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
486  SCIP_VAR* var /**< variable to increase usage counter for */
487  )
488 {
489  assert(conshdlrdata != NULL);
490 
491  SCIPdebugMsg(scip, "decreasing varuses of <%s>: %d\n",
492  SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var)));
493 
494  SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, -1) );
495 
496  return SCIP_OKAY;
497 }
498 
499 /** increases the usage counter of all variable in the constraint */
500 static
501 SCIP_RETCODE consdataIncVaruses(
502  SCIP* scip, /**< SCIP data structure */
503  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
504  SCIP_CONSDATA* consdata /**< setppc constraint data */
505  )
506 {
507  int v;
508 
509  assert(consdata != NULL);
510 
511  for( v = 0; v < consdata->nvars; ++v )
512  {
513  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, consdata->vars[v]) );
514  }
515 
516  return SCIP_OKAY;
517 }
518 
519 /** decreases the usage counter of all variable in the constraint */
520 static
521 SCIP_RETCODE consdataDecVaruses(
522  SCIP* scip, /**< SCIP data structure */
523  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
524  SCIP_CONSDATA* consdata /**< setppc constraint data */
525  )
526 {
527  int v;
528 
529  assert(consdata != NULL);
530 
531  for( v = 0; v < consdata->nvars; ++v )
532  {
533  SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, consdata->vars[v]) );
534  }
535 
536  return SCIP_OKAY;
537 }
538 #endif
539 
540 /** ensures, that the vars array can store at least num entries */
541 static
543  SCIP* scip, /**< SCIP data structure */
544  SCIP_CONSDATA* consdata, /**< setppc constraint data */
545  int num /**< minimum number of entries to store */
546  )
547 {
548  assert(consdata != NULL);
549  assert(consdata->nvars <= consdata->varssize);
551  if( num > consdata->varssize )
552  {
553  int newsize;
554 
555  newsize = SCIPcalcMemGrowSize(scip, num);
556  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
557  consdata->varssize = newsize;
558  }
559  assert(num <= consdata->varssize);
560 
561  return SCIP_OKAY;
562 }
563 
564 /** creates a set partitioning / packing / covering constraint data object */
565 static
567  SCIP* scip, /**< SCIP data structure */
568  SCIP_CONSDATA** consdata, /**< pointer to store the set partitioning / packing / covering constraint */
569  int nvars, /**< number of variables in the constraint */
570  SCIP_VAR** vars, /**< variables of the constraint */
571  SCIP_SETPPCTYPE setppctype /**< type of constraint: set partitioning, packing, or covering constraint */
572  )
573 {
574  assert(consdata != NULL);
575  assert(nvars == 0 || vars != NULL);
576 
577  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
578 
579  (*consdata)->signature = 0;
580  (*consdata)->row = NULL;
581  (*consdata)->nlrow = NULL;
582  (*consdata)->existmultaggr = FALSE;
583  (*consdata)->catchevents = FALSE;
584  (*consdata)->nfixedzeros = 0;
585  (*consdata)->nfixedones = 0;
586 
587  if( nvars > 0 )
588  {
589  int v;
590 
591  /* @todo the setppc constraint handler does not remove fixed variables from its var array; removing those
592  * variables is only possible if we consider the values of nfixedones and nfixedzeros in all propagation methods
593  */
594 #ifdef SCIP_DISABLED_CODE
595 
596  if( SCIPisConsCompressionEnabled(scip) )
597  {
598  SCIP_VAR** varsbuffer;
599  int k;
600 
601  /* allocate temporary buffer storage for active variables */
602  SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
603 
604  k = 0;
605  /* collect fixed variables to compress the required memory */
606  for( v = 0; v < nvars; ++v )
607  {
608  assert(SCIPvarIsBinary(vars[v]));
609 
610  /* already fixed variables account as fixed ones or zero, only unfixed are appended */
611  if( SCIPvarGetLbGlobal(vars[v]) > 0.5 )
612  (*consdata)->nfixedones++;
613  else if( SCIPvarGetUbGlobal(vars[v]) < 0.5 )
614  (*consdata)->nfixedzeros++;
615  else
616  varsbuffer[k++] = vars[v];
617  }
618 
619  (*consdata)->varssize = k;
620  (*consdata)->nvars = k;
621  /* copy unfixed variables into constraint data */
622  if( k > 0 )
623  {
624  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
625  }
626 
627  /* free temporary storage */
628  SCIPfreeBufferArray(scip, &varsbuffer);
629  }
630  else
631 #endif
632  {
633  /* for uncompressed copies, simply duplicate the whole array */
634  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
635  (*consdata)->varssize = nvars;
636  (*consdata)->nvars = nvars;
637  }
638 
639  if( SCIPisTransformed(scip) )
640  {
641  /* get transformed variables */
642  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
643 
644  /* check for multi-aggregations and capture variables */
645  for( v = 0; v < (*consdata)->nvars; v++ )
646  {
647  SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
648  assert(var != NULL);
649  (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
650  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
651  }
652  }
653  else
654  {
655  /* capture variables */
656  for( v = 0; v < (*consdata)->nvars; v++ )
657  {
658  assert((*consdata)->vars[v] != NULL);
659  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
660  }
661  }
662  }
663  else
664  {
665  (*consdata)->vars = NULL;
666  (*consdata)->varssize = 0;
667  (*consdata)->nvars = 0;
668  }
669  (*consdata)->setppctype = setppctype; /*lint !e641*/
670  (*consdata)->sorted = (nvars <= 1);
671  (*consdata)->cliqueadded = FALSE;
672  (*consdata)->validsignature = FALSE;
673  (*consdata)->changed = TRUE;
674  (*consdata)->varsdeleted = FALSE;
675  (*consdata)->merged = FALSE;
676  (*consdata)->presolpropagated = FALSE;
677 
678  return SCIP_OKAY;
679 }
680 
681 /** creates a transformed set partitioning / packing / covering constraint data object */
682 static
684  SCIP* scip, /**< SCIP data structure */
685  SCIP_CONSDATA** consdata, /**< pointer to store the set partitioning / packing / covering constraint */
686  int nvars, /**< number of variables in the constraint */
687  SCIP_VAR** vars, /**< variables of the constraint */
688  SCIP_SETPPCTYPE setppctype /**< type of constraint: set partitioning, packing, or covering constraint */
689  )
690 {
691  assert(consdata != NULL);
692  assert(nvars == 0 || vars != NULL);
693 
694  /* create constraint data */
695  SCIP_CALL( consdataCreate(scip, consdata, nvars, vars, setppctype) );
696 
697  /* transform the variables */
698  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
699 
700  return SCIP_OKAY;
701 }
702 
703 /** frees a set partitioning / packing / covering constraint data */
704 static
706  SCIP* scip, /**< SCIP data structure */
707  SCIP_CONSDATA** consdata /**< pointer to store the set partitioning / packing / covering constraint */
708  )
709 {
710  int v;
711 
712  assert(consdata != NULL);
713  assert(*consdata != NULL);
714 
715  /* release the row */
716  if( (*consdata)->row != NULL )
717  {
718  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
719  }
720 
721  /* release the nlrow */
722  if( (*consdata)->nlrow != NULL )
723  {
724  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
725  }
726 
727  /* release variables */
728  for( v = 0; v < (*consdata)->nvars; v++ )
729  {
730  assert((*consdata)->vars[v] != NULL);
731  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
732  }
733 
734  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->varssize);
735  SCIPfreeBlockMemory(scip, consdata);
736 
737  return SCIP_OKAY;
738 }
739 
740 /** prints set partitioning / packing / covering constraint to file stream */
741 static
743  SCIP* scip, /**< SCIP data structure */
744  SCIP_CONSDATA* consdata, /**< set partitioning / packing / covering constraint data */
745  FILE* file /**< output file (or NULL for standard output) */
746  )
747 {
748  assert(consdata != NULL);
749 
750  /* print coefficients */
751  if( consdata->nvars == 0 )
752  SCIPinfoMessage(scip, file, "0 ");
753 
754  /* write linear sum */
755  SCIP_CALL( SCIPwriteVarsLinearsum(scip, file, consdata->vars, NULL, consdata->nvars, TRUE) );
756 
757  /* print right hand side */
758  switch( consdata->setppctype )
759  {
761  SCIPinfoMessage(scip, file, " == 1");
762  break;
764  SCIPinfoMessage(scip, file, " <= 1");
765  break;
767  SCIPinfoMessage(scip, file, " >= 1");
768  break;
769  default:
770  SCIPerrorMessage("unknown setppc type\n");
771  return SCIP_ERROR;
772  }
773 
774  return SCIP_OKAY;
775 }
776 
777 /** returns the bit signature of the given constraint data */
778 static
779 uint64_t consdataGetSignature(
780  SCIP_CONSDATA* consdata /**< set partitioning / packing / covering constraint data */
781  )
782 {
783  assert(consdata != NULL);
784 
785  if( !consdata->validsignature )
786  {
787  int i;
788 
789  consdata->signature = 0;
790  for( i = 0; i < consdata->nvars; ++i )
791  consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(consdata->vars[i]));
792  consdata->validsignature = TRUE;
793  }
794 
795  return consdata->signature;
796 }
797 
798 /** sorts setppc constraint's variables by non-decreasing variable index */
799 static
800 void consdataSort(
801  SCIP_CONSDATA* consdata /**< linear constraint data */
802  )
803 {
804  assert(consdata != NULL);
805 
806  if( !consdata->sorted )
807  {
808  if( consdata->nvars <= 1 )
809  consdata->sorted = TRUE;
810  else
811  {
812  SCIPsortPtr((void**)consdata->vars, SCIPvarComp, consdata->nvars);
813  consdata->sorted = TRUE;
814  }
815  }
816  assert(consdata->sorted);
817 #ifdef SCIP_DEBUG
818  /* check sorting */
819  {
820  int v;
821 
822  for( v = 0; v < consdata->nvars; ++v )
823  {
824  assert(v == consdata->nvars-1 || SCIPvarCompare(consdata->vars[v], consdata->vars[v+1]) <= 0);
825  }
826  }
827 #endif
828 }
829 
830 /** changes the type of a setppc constraint */
831 static
833  SCIP* scip, /**< SCIP data structure */
834  SCIP_CONS* cons, /**< setppc constraint */
835  SCIP_SETPPCTYPE setppctype /**< new type of constraint */
836  )
837 {
838  SCIP_CONSHDLR* conshdlr;
839  SCIP_CONSHDLRDATA* conshdlrdata;
840  SCIP_CONSDATA* consdata;
841  SCIP_Bool locked;
842  int i;
843 
844  consdata = SCIPconsGetData(cons);
845  assert(consdata != NULL);
846 
847  if( (SCIP_SETPPCTYPE)consdata->setppctype == setppctype )
848  return SCIP_OKAY;
849 
850  SCIPdebugMsg(scip, " -> converting <%s> into setppc type %d\n", SCIPconsGetName(cons), setppctype);
851 
852  /* remove rounding locks */
853  locked = FALSE;
854  for( i = 0; i < NLOCKTYPES && !locked; i++ )
855  locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i);
856 
857  if( locked )
858  {
859  for( i = 0; i < consdata->nvars; ++i )
860  {
861  SCIP_CALL( unlockRounding(scip, cons, consdata->vars[i]) );
862  }
863  }
864 
865  conshdlr = SCIPconsGetHdlr(cons);
866  assert(conshdlr != NULL);
867  conshdlrdata = SCIPconshdlrGetData(conshdlr);
868  assert(conshdlrdata != NULL);
869 
870  if( SCIPisTransformed(scip) )
871  {
872  if( setppctype == SCIP_SETPPCTYPE_PARTITIONING )
873  {
874  ++(conshdlrdata->nsetpart);
875  assert(conshdlrdata->nsetpart >= 0);
876  }
877  else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
878  {
879  --(conshdlrdata->nsetpart);
880  assert(conshdlrdata->nsetpart >= 0);
881  }
882  }
883 
884  /* change the constraint type */
885  consdata->setppctype = setppctype; /*lint !e641*/
886 
887  /* reinstall rounding locks again */
888  if( locked )
889  {
890  for( i = 0; i < consdata->nvars; ++i )
891  {
892  SCIP_CALL( lockRounding(scip, cons, consdata->vars[i]) );
893  }
894  }
895 
896  /* remember that we changed a constraint type for clique lifting procedure */
897  if( setppctype != SCIP_SETPPCTYPE_COVERING )
898  conshdlrdata->updatedsetppctype = TRUE;
899 
900  return SCIP_OKAY;
901 }
902 
903 /** catches events for variable at given position */
904 static
906  SCIP* scip, /**< SCIP data structure */
907  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
908  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
909  int pos /**< array position of variable to catch bound change events for */
910  )
911 {
912  SCIP_CONSDATA* consdata;
913  SCIP_EVENTTYPE eventtype;
914  SCIP_VAR* var;
915 
916  consdata = SCIPconsGetData(cons);
917  assert(consdata != NULL);
918  assert(eventhdlr != NULL);
919  assert(0 <= pos && pos < consdata->nvars);
920  assert(consdata->vars != NULL);
921 
922  var = consdata->vars[pos];
923  assert(var != NULL);
924 
925  /* we are catching the following events:
926  *
927  * - SCIP_EVENTTYPE_BOUNDCHANGED: Is used to count the number of variable fixed locally to zero and one. That helps
928  * to speed up the propagation
929  *
930  * - SCIP_EVENTTYPE_VARDELETED: Is caught to remove a deleted variable from the constraint
931  *
932  * - SCIP_EVENTTYPE_VARFIXED: Is used to get informed if a variable of the constraint was aggregated which means was
933  * detected to be equal or a negated variable of on other variable. in case of a negation
934  * this could lead to a redundant constraint if the (other) active variable is also part
935  * of the constraint.
936  */
938 
939  /* catch bound change events on variable */
940  SCIP_CALL( SCIPcatchVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) );
941 
942  /* update the fixed variables counters for this variable */
943  if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
944  {
945  consdata->nfixedzeros++;
946 
947  /* during presolving, we may fix the last unfixed variable or do an aggregation if there are two unfixed variables */
948  if( SCIPconsIsActive(cons) && ((SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE) && (consdata->nfixedzeros >= consdata->nvars - 2)) )
949  {
950  consdata->presolpropagated = FALSE;
951 
952  /* during solving, we only propagate again if there is only one unfixed variable left */
953  if( consdata->nfixedzeros >= consdata->nvars - 1 )
954  {
955  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
956  }
957  }
958  }
959  else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
960  {
961  consdata->nfixedones++;
962 
963  if( SCIPconsIsActive(cons) )
964  {
965  consdata->presolpropagated = FALSE;
966  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
967  }
968  }
969 
970  return SCIP_OKAY;
971 }
972 
973 /** drops events for variable at given position */
974 static
976  SCIP* scip, /**< SCIP data structure */
977  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
978  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
979  int pos /**< array position of variable to catch bound change events for */
980  )
981 {
982  SCIP_CONSDATA* consdata;
983  SCIP_EVENTTYPE eventtype;
984  SCIP_VAR* var;
985 
986  consdata = SCIPconsGetData(cons);
987  assert(consdata != NULL);
988  assert(eventhdlr != NULL);
989  assert(0 <= pos && pos < consdata->nvars);
990  assert(consdata->vars != NULL);
991 
992  var = consdata->vars[pos];
993  assert(var != NULL);
994 
996 
997  /* drop events on variable */
998  SCIP_CALL( SCIPdropVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, -1) );
999 
1000  /* update the fixed variables counters for this variable */
1001  if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
1002  consdata->nfixedzeros--;
1003  else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
1004  consdata->nfixedones--;
1005 
1006  return SCIP_OKAY;
1007 }
1008 
1009 /** catches bound change events for all variables in transformed setppc constraint */
1010 static
1012  SCIP* scip, /**< SCIP data structure */
1013  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
1014  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1015  )
1016 {
1017  SCIP_CONSDATA* consdata;
1018  int i;
1020  consdata = SCIPconsGetData(cons);
1021  assert(consdata != NULL);
1022 
1023  if( consdata->catchevents == TRUE )
1024  return SCIP_OKAY;
1025 
1026  /* catch event for every single variable */
1027  for( i = 0; i < consdata->nvars; ++i )
1028  {
1029  SCIP_CALL( catchEvent(scip, cons, eventhdlr, i) );
1030  }
1031 
1032  consdata->catchevents = TRUE;
1033 
1034  return SCIP_OKAY;
1035 }
1036 
1037 /** drops bound change events for all variables in transformed setppc constraint */
1038 static
1040  SCIP* scip, /**< SCIP data structure */
1041  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
1042  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1043  )
1044 {
1045  SCIP_CONSDATA* consdata;
1046  int i;
1048  consdata = SCIPconsGetData(cons);
1049  assert(consdata != NULL);
1050 
1051  if( consdata->catchevents == FALSE )
1052  return SCIP_OKAY;
1053 
1054  /* drop event of every single variable */
1055  for( i = 0; i < consdata->nvars; ++i )
1056  {
1057  SCIP_CALL( dropEvent(scip, cons, eventhdlr, i) );
1058  }
1059 
1060  consdata->catchevents = FALSE;
1061 
1062  return SCIP_OKAY;
1063 }
1064 
1065 /** adds coefficient in setppc constraint */
1066 static
1068  SCIP* scip, /**< SCIP data structure */
1069  SCIP_CONS* cons, /**< setppc constraint */
1070  SCIP_VAR* var /**< variable to add to the constraint */
1071  )
1072 {
1073  SCIP_CONSDATA* consdata;
1074  SCIP_Bool transformed;
1076  assert(var != NULL);
1077 
1078  consdata = SCIPconsGetData(cons);
1079  assert(consdata != NULL);
1080 
1081  /* are we in the transformed problem? */
1082  transformed = SCIPconsIsTransformed(cons);
1083 
1084  /* always use transformed variables in transformed constraints */
1085  if( transformed )
1086  {
1087  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1088  }
1089  assert(var != NULL);
1090  assert(transformed == SCIPvarIsTransformed(var));
1091 
1092  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
1093  consdata->vars[consdata->nvars] = var;
1094  consdata->nvars++;
1095  if( consdata->validsignature )
1096  consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(var));
1097  consdata->sorted = (consdata->nvars == 1);
1098  consdata->changed = TRUE;
1099 
1100  /* capture the variable */
1101  SCIP_CALL( SCIPcaptureVar(scip, var) );
1102 
1103  /* if we are in transformed problem, catch the variable's events */
1104  if( transformed )
1105  {
1106  SCIP_CONSHDLR* conshdlr;
1107  SCIP_CONSHDLRDATA* conshdlrdata;
1108 
1109  /* get event handler */
1110  conshdlr = SCIPconsGetHdlr(cons);
1111  assert(conshdlr != NULL);
1112  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1113  assert(conshdlrdata != NULL);
1114  assert(conshdlrdata->eventhdlr != NULL);
1115 
1116  /* catch bound change events of variable */
1117  if( consdata->catchevents )
1118  {
1119  SCIP_CALL( catchEvent(scip, cons, conshdlrdata->eventhdlr, consdata->nvars-1) );
1120  }
1121 
1122  if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
1123  consdata->existmultaggr = TRUE;
1124 
1125 #ifdef VARUSES
1126  /* if the constraint is currently active, increase the variable usage counter */
1127  if( SCIPconsIsActive(cons) )
1128  {
1129  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) );
1130  }
1131 #endif
1132  }
1133 
1134  /* install the rounding locks for the new variable */
1135  SCIP_CALL( lockRounding(scip, cons, var) );
1136 
1137  /* add the new coefficient to the LP row */
1138  if( consdata->row != NULL )
1139  {
1140  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, 1.0) );
1141  }
1142 
1143  consdata->merged = FALSE;
1144  consdata->cliqueadded = FALSE;
1145 
1146  return SCIP_OKAY;
1147 }
1148 
1149 /** deletes coefficient at given position from setppc constraint data */
1150 static
1152  SCIP* scip, /**< SCIP data structure */
1153  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
1154  int pos /**< position of coefficient to delete */
1155  )
1156 {
1157  SCIP_CONSDATA* consdata;
1158  SCIP_VAR* var;
1160  assert(scip != NULL);
1161  assert(cons != NULL);
1162 
1163  consdata = SCIPconsGetData(cons);
1164  assert(consdata != NULL);
1165  assert(0 <= pos && pos < consdata->nvars);
1166 
1167  var = consdata->vars[pos];
1168  assert(var != NULL);
1169  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1170 
1171  /* remove the rounding locks for the deleted variable */
1172  SCIP_CALL( unlockRounding(scip, cons, var) );
1173 
1174  /* if we are in transformed problem, delete the event data of the variable */
1175  if( SCIPconsIsTransformed(cons) )
1176  {
1177  SCIP_CONSHDLR* conshdlr;
1178  SCIP_CONSHDLRDATA* conshdlrdata;
1179 
1180  /* get event handler */
1181  conshdlr = SCIPconsGetHdlr(cons);
1182  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1183  assert(conshdlrdata != NULL);
1184  assert(conshdlrdata->eventhdlr != NULL);
1185 
1186  /* drop bound change events of variable */
1187  if( consdata->catchevents )
1188  {
1189  SCIP_CALL( dropEvent(scip, cons, conshdlrdata->eventhdlr, pos) );
1190  }
1191 
1192  /* the last variable of the constraint was deleted; mark it for propagation (so that it can be deleted) */
1193  if( consdata->nvars == 1 )
1194  {
1195  consdata->presolpropagated = FALSE;
1196  }
1197  }
1198 
1199  /* delete coefficient from the LP row */
1200  if( consdata->row != NULL )
1201  {
1202  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -1.0) );
1203  }
1204 
1205  /* move the last variable to the free slot */
1206  if( pos != consdata->nvars - 1 )
1207  {
1208  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
1209  consdata->sorted = FALSE;
1210  }
1211  consdata->nvars--;
1212  consdata->validsignature = FALSE;
1213  consdata->changed = TRUE;
1214 
1215  /* release variable */
1216  SCIP_CALL( SCIPreleaseVar(scip, &var) );
1217 
1218  return SCIP_OKAY;
1219 }
1220 
1221 /** in case a part (more than one variable) in the setppc constraint is independent of every else (is locked only by
1222  * this constraint), we can perform dual reductions;
1223  *
1224  * (1) set covering
1225  *
1226  * - fix all independent variables with negative object coefficient to one
1227  * - fix all remaining independent variables to zero
1228  *
1229  * (i) all variables are independent and the constraint is not modifiable
1230  *
1231  * - fix the variable with the smallest object coefficient to one
1232  *
1233  * (ii) a variable x has exactly 0 uplocks and arbitrary downlocks and a variable y has exactly 1 downlock and
1234  * arbitrary uplocks and obj(x) <= obj(y) and obj(y) >= 0
1235  *
1236  * - fix y to 0, because it is dominated by x
1237  *
1238  * (2) set partitioning
1239  *
1240  * (i) all variables are independent and the constraint is not modifiable
1241  *
1242  * - fix the variable with the smallest object coefficient to one
1243  * - fix all remaining independent variables to zero
1244  *
1245  * (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 1 downlock and
1246  * arbitrary uplocks and obj(x) <= obj(y)
1247  *
1248  * - fix y to 0, because it is dominated by x
1249  *
1250  * (3) set packing
1251  *
1252  * (i) all variables are independent and the constraint is not modifiable
1253  *
1254  * - fix the variable with the smallest object coefficient to one if the object coefficient is negative or zero
1255  * - fix all remaining independent variables to zero
1256  *
1257  * (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 0 downlocks and
1258  * arbitrary uplocks and obj(x) <= obj(y)
1259  *
1260  * - fix y to 0, because it is dominated by x
1261  *
1262  *
1263  * Note: the following dual reduction for set covering and set packing constraints is already performed by the presolver
1264  * "dualfix"
1265  * (1) in case of a set covering constraint the following dual reduction can be performed:
1266  * - if a variable in a set covering constraint is only locked by that constraint and has negative or zero
1267  * objective coefficient than it can be fixed to one
1268  * (2) in case of a set packing constraint the following dual reduction can be performed:
1269  * - if a variable in a set packing constraint is only locked by that constraint and has positive or zero
1270  * objective coefficient than it can be fixed to zero
1271  *
1272  * Note: all dual reduction (ii) could also be performed by the "domcol" presolver, but cause the pairwise comparison of
1273  * columns is only done heuristically (and here it should be even cheaper) we perform them here (too)
1274  *
1275  */
1276 static
1278  SCIP* scip, /**< SCIP data structure */
1279  SCIP_CONS* cons, /**< setppc constraint */
1280  int* nfixedvars, /**< pointer to count number of fixings */
1281  int* ndelconss, /**< pointer to count number of deleted constraints */
1282  SCIP_RESULT* result /**< pointer to store the result SCIP_SUCCESS, if presolving was performed */
1283  )
1284 {
1285  SCIP_CONSDATA* consdata;
1286  SCIP_SETPPCTYPE setppctype;
1287  SCIP_VAR** vars;
1288  SCIP_VAR* activevar;
1289  SCIP_VAR* var;
1290  SCIP_Real bestobjval;
1291  SCIP_Real objval;
1292  SCIP_Real fixval;
1293  SCIP_Bool infeasible;
1294  SCIP_Bool fixed;
1295  SCIP_Bool negated;
1296  int noldfixed;
1297  int nposfixings;
1298  int nlockdowns;
1299  int nlockups;
1300  int nvars;
1301  int idx;
1302  int v;
1303 
1304  assert(scip != NULL);
1305  assert(cons != NULL);
1306  assert(nfixedvars != NULL);
1307  assert(ndelconss != NULL);
1308  assert(result != NULL);
1309 
1310  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
1311  * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
1312  * added to the problems have the check flag set to FALSE
1313  */
1314  if( !SCIPconsIsChecked(cons) )
1315  return SCIP_OKAY;
1316 
1317  assert(SCIPconsIsActive(cons));
1318 
1319  consdata = SCIPconsGetData(cons);
1320  assert(consdata != NULL);
1321 
1322  /* modifiable non-covering constraints cannot be deleted if one variable is fixed to one, because the propagation for
1323  * newly inserted variables must be considered later
1324  */
1325  if( consdata->nfixedones == 1 && SCIPconsIsModifiable(cons) )
1326  return SCIP_OKAY;
1327 
1328  /* all fixed variables should be removed at that point */
1329  assert(consdata->nfixedones == 0);
1330  assert(consdata->nfixedzeros == 0);
1331 
1332  nvars = consdata->nvars;
1333 
1334  /* we don't want to consider small constraints (note that the constraints can be modifiable, so we can't delete this
1335  * constraint)
1336  */
1337  if( nvars < 2 )
1338  return SCIP_OKAY;
1339 
1340  setppctype = (SCIP_SETPPCTYPE)consdata->setppctype;
1341  vars = consdata->vars;
1342  idx = -1;
1343  bestobjval = SCIP_INVALID;
1344 
1345  /* collect the rounding locks depending on the setppc type */
1346  switch( setppctype )
1347  {
1349  nlockdowns = 1;
1350  nlockups = 1;
1351  break;
1353  nlockdowns = 0;
1354  nlockups = 1;
1355  break;
1357  nlockdowns = 1;
1358  nlockups = 0;
1359  break;
1360  default:
1361  SCIPerrorMessage("unknown setppc type\n");
1362  SCIPABORT();
1363  return SCIP_INVALIDDATA; /*lint !e527*/
1364  }
1365 
1366  nposfixings = 0;
1367 
1368  /* check if we can apply the dual reduction; therefore count the number of variables where the setppc has the only
1369  * locks on this constraint
1370  */
1371  for( v = 0; v < nvars; ++v )
1372  {
1373  var = vars[v];
1374  assert(var != NULL);
1375 
1376  /* the variable should not be (globally) fixed */
1377  assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
1378 
1379  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) >= nlockdowns
1380  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == nlockups )
1381  {
1382  activevar = var;
1383  negated = FALSE;
1384 
1385  /* get the active variable */
1386  SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1387  assert(SCIPvarIsActive(activevar));
1388 
1389  if( negated )
1390  objval = -SCIPvarGetObj(activevar);
1391  else
1392  objval = SCIPvarGetObj(activevar);
1393 
1394  /* check if the current variable has a smaller objective coefficient */
1395  if( idx == -1 || objval < bestobjval )
1396  {
1397  idx = v;
1398  bestobjval = objval;
1399  }
1400  }
1401 
1402  /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1403  * variables
1404  */
1405  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1406  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1407  ++nposfixings;
1408  }
1409 
1410  if( idx == -1 || nposfixings == 0 )
1411  return SCIP_OKAY;
1412 
1413  SCIPdebugMsg(scip, "dual fixing constraint: \n");
1414  SCIPdebug( SCIP_CALL( SCIPprintCons(scip, cons, NULL) ) );
1415  SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") );
1416 
1417  assert(idx >= 0 && idx < nvars);
1418  assert(bestobjval < SCIPinfinity(scip));
1419 
1420  noldfixed = *nfixedvars;
1421 
1422  /* in case of set packing and set partitioning we fix the dominated variables to zero */
1423  if( setppctype != SCIP_SETPPCTYPE_COVERING )
1424  {
1425  /* first part of all variables */
1426  for( v = nvars - 1; v >= 0; --v )
1427  {
1428  if( v == idx )
1429  continue;
1430 
1431  var = vars[v];
1432  assert(var != NULL);
1433 
1434  /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1435  * variables
1436  */
1437  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1438  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1439  {
1440  activevar = var;
1441  negated = FALSE;
1442 
1443  /* get the active variable */
1444  SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1445  assert(SCIPvarIsActive(activevar));
1446 
1447  if( negated )
1448  objval = -SCIPvarGetObj(activevar);
1449  else
1450  objval = SCIPvarGetObj(activevar);
1451 
1452  if( objval >= bestobjval )
1453  {
1454  SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
1455  assert(!infeasible);
1456  assert(fixed);
1457 
1458  SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == 0.0\n", SCIPvarGetName(var));
1459  ++(*nfixedvars);
1460  }
1461  }
1462  }
1463  }
1464  /* if we got a set covering constraint and not all variables are locked from this constraint it might not get
1465  * redundant (which is case if it is not possible to fix at least one variable to one), we fix all redundant
1466  * variables to their best bound
1467  */
1468  else
1469  {
1470  /* first part of all variables */
1471  for( v = nvars - 1; v >= 0; --v )
1472  {
1473  if( v == idx )
1474  continue;
1475 
1476  var = vars[v];
1477  assert(var != NULL);
1478 
1479  /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1480  * variables
1481  */
1482  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1483  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1484  {
1485  activevar = var;
1486  negated = FALSE;
1487 
1488  /* get the active variable */
1489  SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1490  assert(SCIPvarIsActive(activevar));
1491  assert(negated
1494  assert(!negated
1497 
1498  if( negated )
1499  objval = -SCIPvarGetObj(activevar);
1500  else
1501  objval = SCIPvarGetObj(activevar);
1502 
1503  if( objval > 0.0 )
1504  fixval = 0.0;
1505  else
1506  fixval = 1.0;
1507 
1508  /* if variables has a negative objective contribution, and is uplocked by another constraint we cannot fix
1509  * the variables to 1
1510  */
1511  if( (fixval == 1.0 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > nlockups) || objval < bestobjval )
1512  continue;
1513 
1514  SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeasible, &fixed) );
1515  assert(!infeasible);
1516  assert(fixed);
1517 
1518  SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == %g\n", SCIPvarGetName(var), fixval);
1519  ++(*nfixedvars);
1520  }
1521  }
1522  }
1523 
1524  /* if all variables but the domination variable is fixed and the constraint is not modifiable or the constraint is a
1525  * covering constraint and the bestobjval is less than or equal to zero, we can fix the domination variable (with best
1526  * objective coefficient) and the constraint gets redundant
1527  */
1528  if( ((*nfixedvars - noldfixed == nvars - 1) && !SCIPconsIsModifiable(cons)) || (setppctype == SCIP_SETPPCTYPE_COVERING && bestobjval <= 0.0) )
1529  {
1530  /* in case of a set packing constraint with positive objective values, all variables can be fixed to zero; in all
1531  * other cases the variable with the smallest objective values is fixed to one
1532  */
1533  if( (setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0
1534  && SCIPvarGetNLocksDownType(vars[idx], SCIP_LOCKTYPE_MODEL) == 0)
1535  || setppctype != SCIP_SETPPCTYPE_PACKING || bestobjval <= 0.0 )
1536  {
1537  if( setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0 )
1538  fixval = 0.0;
1539  else
1540  fixval = 1.0;
1541 
1542  SCIP_CALL( SCIPfixVar(scip, vars[idx], fixval, &infeasible, &fixed) );
1543  assert(!infeasible);
1544  assert(fixed);
1545 
1546  SCIPdebugMsg(scip, " -> dual-fixed best variable <%s> == %g\n", SCIPvarGetName(vars[idx]), fixval);
1547  ++(*nfixedvars);
1548  }
1549 
1550  /* check that we really have a non-violated constraint in hand before deleting */
1551  assert((setppctype == SCIP_SETPPCTYPE_PACKING && consdata->nfixedones <= 1) ||
1552  (setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedones == 1) ||
1553  (setppctype == SCIP_SETPPCTYPE_COVERING && consdata->nfixedones >= 1));
1554 
1555  /* remove constraint since it is redundant */
1556  SCIP_CALL( SCIPdelCons(scip, cons) );
1557  ++(*ndelconss);
1558  }
1559 
1560  assert(*nfixedvars >= noldfixed);
1561 
1562  /* set result pointer to SCIP_SUCCESS, if variables could be fixed */
1563  if( *nfixedvars != noldfixed )
1564  *result = SCIP_SUCCESS;
1565 
1566  return SCIP_OKAY;
1567 }
1568 
1569 /** find pairs of negated variables in constraint:
1570  * partitioning/packing: all other variables must be zero, constraint is redundant
1571  * covering: constraint is redundant
1572  *
1573  * find sets of equal variables in constraint:
1574  * partitioning/packing: variable must be zero
1575  * covering: multiple entries of variable can be replaced by single entry
1576  */
1577 static
1579  SCIP* scip, /**< SCIP data structure */
1580  SCIP_CONS* cons, /**< knapsack constraint */
1581  int* nfixedvars, /**< pointer to store number of fixed variables */
1582  int* ndelconss, /**< pointer to store number of deleted constraints */
1583  int* nchgcoefs, /**< pointer to store number of changed coefficients */
1584  SCIP_Bool* cutoff /**< pointer to store whether a fixing leads to a cutoff */
1585  )
1587  SCIP_CONSDATA* consdata;
1588  int v;
1589 
1590  assert(scip != NULL);
1591  assert(cons != NULL);
1592  assert(nfixedvars != NULL);
1593  assert(ndelconss != NULL);
1594  assert(nchgcoefs != NULL);
1595  assert(cutoff != NULL);
1596 
1597  consdata = SCIPconsGetData(cons);
1598  assert(consdata != NULL);
1599 
1600  if( consdata->merged || SCIPconsIsDeleted(cons) )
1601  return SCIP_OKAY;
1602 
1603  if( consdata->nvars <= 1 )
1604  {
1605  consdata->merged = TRUE;
1606  return SCIP_OKAY;
1607  }
1608 
1609  assert(consdata->vars != NULL || consdata->nvars == 0);
1610 
1611  /* sorting array after indices of variables, that's only for faster merging */
1612  SCIPsortPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, consdata->nvars);
1613  /* setppc sorting now lost */
1614  consdata->sorted = FALSE;
1615 
1616  /* loop backwards through the items: deletion only affects rear items */
1617  for( v = consdata->nvars - 1; v > 0; --v )
1618  {
1619  SCIP_VAR* var1;
1620  SCIP_VAR* var2;
1621  SCIP_Bool negated1;
1622  SCIP_Bool negated2;
1623 
1624  negated1 = FALSE;
1625  negated2 = FALSE;
1626 
1627  var1 = consdata->vars[v];
1628  assert(SCIPvarIsBinary(var1));
1631  {
1632  var1 = SCIPvarGetNegatedVar(var1);
1633  negated1 = TRUE;
1634  }
1635  assert(var1 != NULL);
1636 
1637  var2 = consdata->vars[v-1];
1638  assert(SCIPvarIsBinary(var2));
1641  {
1642  var2 = SCIPvarGetNegatedVar(var2);
1643  negated2 = TRUE;
1644  }
1645  assert(var2 != NULL);
1646 
1647  if( var1 == var2 )
1648  {
1649  SCIP_Bool infeasible;
1650  SCIP_Bool fixed;
1651 
1652  /* one variables is active and the other is the same negated variable */
1653  if( negated1 != negated2 )
1654  {
1655  /* all other variable have to be zero if it's a partitioning or packing constraint */
1656  if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
1657  {
1658  int i;
1659 
1660  assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
1661  || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
1662 
1663  for( i = consdata->nvars - 1; i >= 0; --i )
1664  if( i != v && i != (v-1) )
1665  {
1666  SCIP_CALL( SCIPfixVar(scip, consdata->vars[i], 0.0, &infeasible, &fixed) );
1667  if( infeasible )
1668  {
1669  SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
1670  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]));
1671  *cutoff = TRUE;
1672  return SCIP_OKAY;
1673  }
1674 
1675  if( fixed )
1676  ++(*nfixedvars);
1677  }
1678  }
1679  /* all setppc-type constraints are redundant */
1680  SCIP_CALL( SCIPdelCons(scip, cons) );
1681  ++(*ndelconss);
1682  return SCIP_OKAY;
1683  }
1684  /* both variables are either active or negated */
1685  else
1686  {
1687  /* this variable can be fixed to zero if it's a partitioning or packing constraint */
1688  if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
1689  {
1690  assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
1691  || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
1692 
1693  SCIP_CALL( SCIPfixVar(scip, var1, negated1 ? 1.0 : 0.0, &infeasible, &fixed) );
1694  if( infeasible )
1695  {
1696  SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == %g\n",
1697  SCIPconsGetName(cons), SCIPvarGetName(var1), negated1 ? 1.0 : 0.0);
1698  *cutoff = TRUE;
1699  return SCIP_OKAY;
1700  }
1701 
1702  if( fixed )
1703  ++(*nfixedvars);
1704  }
1705  /* multiple entries of variable can be replaced by single entry */
1706  else
1707  {
1708  SCIP_CALL( delCoefPos(scip, cons, v) ); /* only some changed behind position v-1, so it's okay */
1709  ++(*nchgcoefs);
1710  }
1711  }
1712  consdata->changed = TRUE;
1713  }
1714  }
1715  consdata->merged = TRUE;
1716 
1717  return SCIP_OKAY;
1718 }
1719 
1720 /** deletes all zero-fixed variables and replace aggregated variables */
1721 static
1723  SCIP* scip, /**< SCIP data structure */
1724  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
1725  int* naddconss, /**< pointer to count number of added constraints, or NULL indicating we
1726  * can not resolve multi-aggregations
1727  */
1728  int* ndelconss, /**< pointer to count number of deleted constraints, or NULL indicating we
1729  * can not resolve multi-aggregations
1730  */
1731  int* nfixedvars, /**< pointer to store number of fixed variables, or NULL indicating we can
1732  * not resolve multi-aggregations
1733  */
1734  SCIP_Bool* cutoff /**< pointer to store whether a fixing leads to a cutoff, or NULL
1735  * indicating we can not resolve multi-aggregations
1736  */
1737  )
1738 {
1739  SCIP_CONSDATA* consdata;
1740  int v;
1741 
1742  assert(scip != NULL);
1743  assert(cons != NULL);
1744 
1745  consdata = SCIPconsGetData(cons);
1746  assert(consdata != NULL);
1747 
1748  /* all multi-aggregations should be resolved */
1749  consdata->existmultaggr = FALSE;
1750 
1751  v = 0;
1752  while( v < consdata->nvars )
1753  {
1754  SCIP_VAR* var;
1755 
1756  var = consdata->vars[v];
1757  assert(SCIPvarIsBinary(var));
1758 
1759  if( SCIPvarGetUbGlobal(var) < 0.5 )
1760  {
1761  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
1762  SCIP_CALL( delCoefPos(scip, cons, v) );
1763  }
1764  else
1765  {
1766  SCIP_VAR* repvar;
1767  SCIP_Bool negated;
1768 
1769  /* get binary representative of variable */
1770  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
1771 
1772  /* resolve multi-aggregation */
1774  {
1775  SCIP_VAR** consvars;
1776  SCIP_Real* consvals;
1777  SCIP_Real constant = 0.0;
1778  SCIP_Bool easycase;
1779  int nconsvars;
1780  int requiredsize;
1781  int v2;
1782 
1783  nconsvars = 1;
1784  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 1) );
1785  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 1) );
1786  consvars[0] = repvar;
1787  consvals[0] = 1.0;
1788 
1789  /* get active variables for new constraint */
1790  SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) );
1791  /* if space was not enough we need to resize the buffers */
1792  if( requiredsize > nconsvars )
1793  {
1794  SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1795  SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1796 
1797  SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
1798  assert(requiredsize <= nconsvars);
1799  }
1800 
1801  easycase = FALSE;
1802 
1803  if( SCIPisZero(scip, constant) )
1804  {
1805  /* add active representation */
1806  for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1807  {
1808  if( !SCIPvarIsBinary(consvars[v2]) )
1809  break;
1810 
1811  if( !SCIPisEQ(scip, consvals[v2], 1.0) )
1812  break;
1813  }
1814 
1815  if( v2 < 0 )
1816  easycase = TRUE;
1817  }
1818  else if( SCIPisFeasEQ(scip, constant, 1.0) )
1819  {
1820  /* check for another multi-aggregation */
1821  for( v2 = consdata->nvars - 1; v2 > v; --v2 )
1822  {
1823  if( SCIPvarGetStatus(SCIPvarGetProbvar(consdata->vars[v])) == SCIP_VARSTATUS_MULTAGGR )
1824  break;
1825  }
1826 
1827  /* constraint is redundant */
1828  if( v2 == v && nconsvars == 0 )
1829  {
1830  /* we can fix */
1831  if( consdata->nvars > 1 && (SCIP_SETPPCTYPE)consdata->setppctype != SCIP_SETPPCTYPE_COVERING )
1832  {
1833  if( nfixedvars != NULL )
1834  {
1835  SCIP_Bool fixed;
1836 
1837  assert(cutoff != NULL);
1838 
1839  for( v2 = consdata->nvars - 1; v2 >= 0; --v2 )
1840  {
1841  if( consdata->vars[v2] != var )
1842  {
1843  SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(consdata->vars[v2]));
1844 
1845  /* fix all remaining variables to zero, constraint is already feasible or infeasible */
1846  SCIP_CALL( SCIPfixVar(scip, consdata->vars[v2], 0.0, cutoff, &fixed) );
1847  if( *cutoff )
1848  {
1849  SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
1850  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v2]));
1851 
1852  SCIPfreeBufferArray(scip, &consvals);
1853  SCIPfreeBufferArray(scip, &consvars);
1854 
1855  goto TERMINATE;
1856  }
1857 
1858  if( fixed )
1859  ++(*nfixedvars);
1860  }
1861  }
1862  }
1863  }
1864 
1865  if( ndelconss != NULL && (nfixedvars != NULL || consdata->nvars == 1 || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING) )
1866  {
1867  /* delete old constraint */
1868  SCIP_CALL( SCIPdelCons(scip, cons) );
1869  ++(*ndelconss);
1870  }
1871  SCIPfreeBufferArray(scip, &consvals);
1872  SCIPfreeBufferArray(scip, &consvars);
1873 
1874  goto TERMINATE;
1875  }
1876  }
1877 
1878  /* we can easily add the coefficients and still have a setppc constraint */
1879  if( easycase )
1880  {
1881  /* delete old (multi-aggregated) variable */
1882  SCIP_CALL( delCoefPos(scip, cons, v) );
1883 
1884  /* add active representation */
1885  for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1886  {
1887  assert(SCIPvarIsBinary(consvars[v2]));
1888  assert(SCIPvarIsActive(consvars[v2]) || (SCIPvarGetStatus(consvars[v2]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(consvars[v2]))));
1889 
1890  SCIP_CALL( addCoef(scip, cons, consvars[v2]) );
1891  }
1892  }
1893  /* we need to degrade this setppc constraint to a linear constraint */
1894  else if( (ndelconss != NULL && naddconss != NULL) || SCIPconsIsAdded(cons) )
1895  {
1896  char name[SCIP_MAXSTRLEN];
1897  SCIP_CONS* newcons;
1898  SCIP_Real lhs;
1899  SCIP_Real rhs;
1900  int size;
1901  int k;
1902 
1903  /* it might happen that there are more than one multi-aggregated variable, so we need to get the whole
1904  * probvar sum over all variables
1905  */
1906 
1907  size = MAX(nconsvars, 1) + consdata->nvars - 1;
1908 
1909  /* memory needed is at least old number of variables - 1 + number of variables in first multi-aggregation */
1910  SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, size) );
1911  SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, size) );
1912 
1913  nconsvars = consdata->nvars;
1914 
1915  /* add constraint variables to new linear variables */
1916  for( k = consdata->nvars - 1; k >= 0; --k )
1917  {
1918  consvars[k] = consdata->vars[k];
1919  consvals[k] = 1.0;
1920  }
1921 
1922  constant = 0.0;
1923 
1924  /* get active variables for new constraint */
1925  SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize, TRUE) );
1926 
1927  /* if space was not enough (we found another multi-aggregation), we need to resize the buffers */
1928  if( requiredsize > nconsvars )
1929  {
1930  SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1931  SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1932 
1933  SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
1934  assert(requiredsize <= nconsvars);
1935  }
1936 
1937  /* compute sides */
1938  if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
1939  {
1940  lhs = -SCIPinfinity(scip);
1941  rhs = 1.0 - constant;
1942  }
1943  else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
1944  {
1945  lhs = 1.0 - constant;
1946  rhs = 1.0 - constant;
1947  }
1948  else
1949  {
1950  assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING);
1951  lhs = 1.0 - constant;
1952  rhs = SCIPinfinity(scip);
1953  }
1954 
1955  /* create linear constraint */
1956  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
1957  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, nconsvars, consvars, consvals, lhs, rhs,
1958  SCIPconsIsInitial(cons),
1962  SCIP_CALL( SCIPaddCons(scip, newcons) );
1963 
1964  SCIPdebugMsg(scip, "added linear constraint: ");
1965  SCIPdebugPrintCons(scip, newcons, NULL);
1966  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1967 
1968  SCIPfreeBufferArray(scip, &consvals);
1969  SCIPfreeBufferArray(scip, &consvars);
1970 
1971  /* delete old constraint */
1972  SCIP_CALL( SCIPdelCons(scip, cons) );
1973  if( ndelconss != NULL && naddconss != NULL )
1974  {
1975  ++(*ndelconss);
1976  ++(*naddconss);
1977  }
1978 
1979  goto TERMINATE;
1980  }
1981  /* we need to degrade this setppc constraint to a linear constraint*/
1982  else
1983  {
1984  /* check, if the variable should be replaced with the representative */
1985  if( repvar != var )
1986  {
1987  /* delete old (aggregated) variable */
1988  SCIP_CALL( delCoefPos(scip, cons, v) );
1989 
1990  /* add representative instead */
1991  SCIP_CALL( addCoef(scip, cons, repvar) );
1992  }
1993 
1994  SCIPwarningMessage(scip, "setppc constraint <%s> has a multi-aggregated variable, which was not resolved and therefore could lead to aborts\n", SCIPconsGetName(cons));
1995  ++v;
1996  }
1997 
1998  SCIPfreeBufferArray(scip, &consvals);
1999  SCIPfreeBufferArray(scip, &consvars);
2000  }
2001  else
2002  {
2003  /* check, if the variable should be replaced with the representative */
2004  if( repvar != var )
2005  {
2006  /* delete old (aggregated) variable */
2007  SCIP_CALL( delCoefPos(scip, cons, v) );
2008 
2009  /* add representative instead */
2010  SCIP_CALL( addCoef(scip, cons, repvar) );
2011  }
2012  else
2013  ++v;
2014  }
2015  }
2016  }
2017 
2018  TERMINATE:
2019  /* all multi-aggregations should be resolved */
2020  consdata->existmultaggr = FALSE;
2021 
2022  return SCIP_OKAY;
2023 }
2024 
2025 /** analyzes conflicting assignment on given constraint where all of the variables where assigned to zero,
2026  * and adds conflict constraint to problem
2027  */
2028 static
2030  SCIP* scip, /**< SCIP data structure */
2031  SCIP_CONS* cons /**< set partitioning / packing / covering constraint that detected the conflict */
2032  )
2033 {
2034  SCIP_CONSDATA* consdata;
2035  int v;
2036 
2037  /* conflict analysis can only be applied in solving stage and if it is applicable */
2039  return SCIP_OKAY;
2040 
2041  consdata = SCIPconsGetData(cons);
2042  assert(consdata != NULL);
2043  assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
2044  || consdata->setppctype == SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
2045 
2046  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
2048 
2049  for( v = 0; v < consdata->nvars; ++v )
2050  {
2051  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
2052  }
2053 
2054  /* analyze the conflict */
2055  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2056 
2057  return SCIP_OKAY;
2058 }
2059 
2060 /** analyzes conflicting assignment on given constraint where two of the variables where assigned to one,
2061  * and adds conflict constraint to problem
2062  */
2063 static
2065  SCIP* scip, /**< SCIP data structure */
2066  SCIP_CONS* cons /**< set partitioning / packing / covering constraint that detected the conflict */
2067  )
2068 {
2069  SCIP_CONSDATA* consdata;
2070  int v;
2071  int n;
2073  /* conflict analysis can only be applied in solving stage and if it is applicable */
2075  return SCIP_OKAY;
2076 
2077  consdata = SCIPconsGetData(cons);
2078  assert(consdata != NULL);
2079  assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
2080  || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2081 
2082  /* initialize conflict analysis, and add the two variables assigned to one to conflict candidate queue */
2084 
2085  n = 0;
2086  for( v = 0; v < consdata->nvars && n < 2; ++v )
2087  {
2088  if( SCIPvarGetLbLocal(consdata->vars[v]) > 0.5 )
2089  {
2090  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
2091  n++;
2092  }
2093  }
2094  assert(n == 2);
2095 
2096  /* analyze the conflict */
2097  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2098 
2099  return SCIP_OKAY;
2100 }
2101 
2102 /** checks constraint for violation only looking at the fixed variables, applies further fixings if possible */
2103 static
2105  SCIP* scip, /**< SCIP data structure */
2106  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be processed */
2107  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2108  int* nfixedvars, /**< pointer to count number of deleted variables */
2109  SCIP_Bool* addcut, /**< pointer to store whether this constraint must be added as a cut */
2110  SCIP_Bool* mustcheck /**< pointer to store whether this constraint must be checked for feasibility */
2111  )
2113  SCIP_CONSDATA* consdata;
2114 #ifndef NDEBUG
2115  int oldnfixedvars;
2116 #endif
2117 
2118  assert(cons != NULL);
2119  assert(SCIPconsGetHdlr(cons) != NULL);
2120  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2121  assert(cutoff != NULL);
2122  assert(nfixedvars != NULL);
2123  assert(addcut != NULL);
2124  assert(mustcheck != NULL);
2125 
2126 #ifndef NDEBUG
2127  oldnfixedvars = *nfixedvars;
2128 #endif
2129 
2130  consdata = SCIPconsGetData(cons);
2131  assert(consdata != NULL);
2132  assert(consdata->nvars == 0 || consdata->vars != NULL);
2133  assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
2134  assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
2135 
2136  *addcut = FALSE;
2137  *mustcheck = TRUE;
2138 
2139  /*SCIPdebugMsg(scip, "processing constraint <%s> with respect to fixed variables (%d fixed to 0.0, %d fixed to 1.0)\n",
2140  SCIPconsGetName(cons), consdata->nfixedzeros, consdata->nfixedones);*/
2141 
2142  if( consdata->nfixedones == 1 )
2143  {
2144  /* exactly one variable is fixed to 1:
2145  * - a set covering constraint is feasible anyway and can be disabled
2146  * - all other variables in a set partitioning or packing constraint must be zero
2147  */
2148  if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2149  {
2150  SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons));
2151  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2152  }
2153  else
2154  {
2155  if( consdata->nfixedzeros < consdata->nvars - 1 )
2156  {
2157  SCIP_VAR** vars;
2158  SCIP_VAR* var;
2159 #ifndef NDEBUG
2160  SCIP_Bool fixedonefound;
2161 #endif
2162  SCIP_Bool infeasible;
2163  SCIP_Bool tightened;
2164  int nvars;
2165  int v;
2166  int oneidx = -1;
2167 
2168  SCIPdebugMsg(scip, " -> fixing all other variables to zero in set packing/partitioning constraint <%s>\n",
2169  SCIPconsGetName(cons));
2170 
2171  /* unfixed variables exist: fix them to zero;
2172  * this could result in additional variables fixed to one due to aggregations; in this case, the
2173  * constraint is infeasible in local bounds
2174  */
2175  vars = consdata->vars;
2176  nvars = consdata->nvars;
2177 #ifndef NDEBUG
2178  fixedonefound = FALSE;
2179 #endif
2180  for( v = 0; v < nvars && consdata->nfixedones == 1; ++v )
2181  {
2182  var = vars[v];
2183  assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0));
2184  if( SCIPvarGetLbLocal(var) < 0.5 )
2185  {
2186  SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, oneidx, &infeasible, &tightened) );
2187  assert(!infeasible);
2188 
2189  if( tightened )
2190  ++(*nfixedvars);
2191 
2192  SCIPdebugMsg(scip, " -> fixed <%s> to zero (tightened=%u)\n", SCIPvarGetName(var), tightened);
2193  }
2194  else
2195  {
2196 #ifndef NDEBUG
2197  fixedonefound = TRUE;
2198 #endif
2199  oneidx = v;
2200  }
2201  }
2202  /* the fixed to one variable must have been found, and at least one variable must have been fixed */
2203  assert(consdata->nfixedones >= 2 || (fixedonefound && *nfixedvars > oldnfixedvars));
2204 
2205  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2206  }
2207 
2208  /* now all other variables are fixed to zero:
2209  * the constraint is feasible, and if it's not modifiable, it is redundant
2210  */
2211  if( !SCIPconsIsModifiable(cons) && consdata->nfixedones == 1 )
2212  {
2213  SCIPdebugMsg(scip, " -> disabling set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons));
2214  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2215  }
2216  }
2217  *mustcheck = FALSE;
2218  }
2219 
2220  if( consdata->nfixedones >= 2 )
2221  {
2222  /* at least two variables are fixed to 1:
2223  * - a set covering constraint is feasible anyway and can be disabled
2224  * - a set partitioning or packing constraint is infeasible
2225  */
2226  if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2227  {
2228  SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons));
2229  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2230  }
2231  else
2232  {
2233  SCIPdebugMsg(scip, " -> conflict on set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons));
2234 
2235  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2236 
2237  /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
2238  SCIP_CALL( analyzeConflictOne(scip, cons) );
2239 
2240  *cutoff = TRUE;
2241  }
2242  *mustcheck = FALSE;
2243  }
2244  else if( consdata->nfixedzeros == consdata->nvars )
2245  {
2246  /* all variables are fixed to zero:
2247  * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled
2248  * - a set partitioning or covering constraint is infeasible, and if it's unmodifiable, the node
2249  * can be cut off -- otherwise, the constraint must be added as a cut and further pricing must
2250  * be performed
2251  */
2252  assert(consdata->nfixedones == 0);
2253 
2254  if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/
2255  {
2256  if( !SCIPconsIsModifiable(cons) )
2257  {
2258  SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons));
2259  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2260  }
2261  }
2262  else
2263  {
2264  SCIPdebugMsg(scip, " -> set covering/partitioning constraint <%s> is infeasible\n", SCIPconsGetName(cons));
2265 
2266  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2267  if( SCIPconsIsModifiable(cons) )
2268  *addcut = TRUE;
2269  else
2270  {
2271  /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
2272  SCIP_CALL( analyzeConflictZero(scip, cons) );
2273 
2274  *cutoff = TRUE;
2275  }
2276  }
2277  *mustcheck = FALSE;
2278  }
2279  else if( consdata->nfixedzeros == consdata->nvars - 1 && consdata->nfixedones == 0 )
2280  {
2281  /* all variables except one are fixed to zero:
2282  * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled
2283  * - an unmodifiable set partitioning or covering constraint is feasible and can be disabled after the
2284  * remaining variable is fixed to one
2285  * - a modifiable set partitioning or covering constraint must be checked manually
2286  */
2287  if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/
2288  {
2289  if( !SCIPconsIsModifiable(cons) )
2290  {
2291  SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons));
2292  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2293  }
2294  *mustcheck = FALSE;
2295  }
2296  else if( !SCIPconsIsModifiable(cons) )
2297  {
2298  SCIP_VAR** vars;
2299  SCIP_VAR* var;
2300  SCIP_Bool infeasible;
2301  SCIP_Bool tightened;
2302  int nvars;
2303  int v;
2304 
2305  /* search the single variable that can be fixed */
2306  vars = consdata->vars;
2307  nvars = consdata->nvars;
2308  for( v = 0; v < nvars; ++v )
2309  {
2310  var = vars[v];
2311  assert(SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)));
2312  assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0));
2313  if( SCIPvarGetUbLocal(var) > 0.5 )
2314  {
2315  SCIPdebugMsg(scip, " -> fixing remaining variable <%s> to one in set covering/partitioning constraint <%s>\n",
2316  SCIPvarGetName(var), SCIPconsGetName(cons));
2317  SCIP_CALL( SCIPinferBinvarCons(scip, var, TRUE, cons, 0, &infeasible, &tightened) );
2318  assert(!infeasible);
2319  assert(tightened);
2320 
2321  ++(*nfixedvars);
2322  break;
2323  }
2324  }
2325  assert(v < nvars);
2326  assert(consdata->nfixedzeros == consdata->nvars - 1);
2327  assert(consdata->nfixedones == 1);
2328 
2329  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2330  *mustcheck = FALSE;
2331  }
2332  }
2333  assert(consdata->nfixedzeros + consdata->nfixedones <= consdata->nvars);
2334 
2335  return SCIP_OKAY;
2336 }
2337 
2338 /** checks constraint for violation, returns TRUE iff constraint is feasible */
2339 static
2341  SCIP* scip, /**< SCIP data structure */
2342  SCIP_CONSDATA* consdata, /**< set partitioning / packing / covering constraint to be checked */
2343  SCIP_SOL* sol /**< primal CIP solution */
2344  )
2345 {
2346  SCIP_VAR** vars;
2347  SCIP_Real solval;
2349  SCIP_Real sumbound;
2350  SCIP_Real absviol;
2351  SCIP_Real relviol;
2352  SCIP_Bool check;
2353  int nvars;
2354  int v;
2355 
2356  /* calculate the constraint's activity */
2357  vars = consdata->vars;
2358  nvars = consdata->nvars;
2359  sum = 0.0;
2360  sumbound = ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING ? 1.0 : 1.0 + 2*SCIPfeastol(scip));
2361  for( v = 0; v < nvars && sum < sumbound; ++v ) /* if sum >= sumbound, the feasibility is clearly decided */
2362  {
2363  assert(SCIPvarIsBinary(vars[v]));
2364 
2365  solval = SCIPgetSolVal(scip, sol, vars[v]);
2366  assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0));
2367 
2368  sum += solval;
2369  }
2370 
2371  absviol = sum - 1.0;
2372  relviol = SCIPrelDiff(sum, 1.0);
2373  switch( consdata->setppctype )
2374  {
2376  /* in case of partitioning, the violation is equal to the absolute difference between sum and 1 */
2377  absviol = REALABS(absviol);
2378  relviol = REALABS(relviol);
2379  check = SCIPisFeasEQ(scip, sum, 1.0);
2380  break;
2382  /* in case of packing, the violation is equal to how much sum exceeds 1 */
2383  check = SCIPisFeasLE(scip, sum, 1.0);
2384  break;
2386  /* in case of covering, the violation is equal to how much 1 exceeds sum */
2387  absviol = -absviol;
2388  relviol = -relviol;
2389  check = SCIPisFeasGE(scip, sum, 1.0);
2390  break;
2391  default:
2392  SCIPerrorMessage("unknown setppc type\n");
2393  SCIPABORT();
2394  return FALSE; /*lint !e527*/
2395  }
2396 
2397  if( sol != NULL )
2398  SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
2399 
2400  return check;
2401 }
2402 
2403 /** creates an LP row in a set partitioning / packing / covering constraint data object */
2404 static
2406  SCIP* scip, /**< SCIP data structure */
2407  SCIP_CONS* cons /**< set partitioning / packing / covering constraint */
2408  )
2409 {
2410  SCIP_CONSDATA* consdata;
2411  SCIP_Real lhs;
2412  SCIP_Real rhs;
2414  consdata = SCIPconsGetData(cons);
2415  assert(consdata != NULL);
2416  assert(consdata->row == NULL);
2417 
2418  switch( consdata->setppctype )
2419  {
2421  lhs = 1.0;
2422  rhs = 1.0;
2423  break;
2425  lhs = -SCIPinfinity(scip);
2426  rhs = 1.0;
2427  break;
2429  lhs = 1.0;
2430  rhs = SCIPinfinity(scip);
2431  break;
2432  default:
2433  SCIPerrorMessage("unknown setppc type\n");
2434  return SCIP_INVALIDDATA;
2435  }
2436 
2437  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), lhs, rhs,
2439 
2440  SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->row, consdata->nvars, consdata->vars, 1.0) );
2441 
2442  return SCIP_OKAY;
2443 }
2444 
2445 /** adds setppc constraint as cut to the LP */
2446 static
2448  SCIP* scip, /**< SCIP data structure */
2449  SCIP_CONS* cons, /**< setppc constraint */
2450  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
2451  )
2452 {
2453  SCIP_CONSDATA* consdata;
2454 
2455  assert( cutoff != NULL );
2456  *cutoff = FALSE;
2457 
2458  consdata = SCIPconsGetData(cons);
2459  assert(consdata != NULL);
2460 
2461  if( consdata->row == NULL )
2462  {
2463  /* convert set partitioning constraint data into LP row */
2464  SCIP_CALL( createRow(scip, cons) );
2465  }
2466  assert(consdata->row != NULL);
2467 
2468  /* insert LP row as cut */
2469  if( !SCIProwIsInLP(consdata->row) )
2470  {
2471  SCIPdebugMsg(scip, "adding constraint <%s> as cut to the LP\n", SCIPconsGetName(cons));
2472  SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
2473  }
2474 
2475  return SCIP_OKAY;
2476 }
2477 
2478 /** adds setppc constraint as row to the NLP, if not added yet */
2479 static
2481  SCIP* scip, /**< SCIP data structure */
2482  SCIP_CONS* cons /**< setppc constraint */
2483  )
2484 {
2485  SCIP_CONSDATA* consdata;
2486 
2487  assert(SCIPisNLPConstructed(scip));
2489  /* skip deactivated, redundant, or local constraints (the NLP does not allow for local rows at the moment) */
2490  if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
2491  return SCIP_OKAY;
2492 
2493  consdata = SCIPconsGetData(cons);
2494  assert(consdata != NULL);
2495 
2496  if( consdata->nlrow == NULL )
2497  {
2498  SCIP_Real lhs, rhs;
2499  SCIP_Real* coefs;
2500  int i;
2501 
2502  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
2503  for( i = 0; i < consdata->nvars; ++i )
2504  coefs[i] = 1.0;
2505 
2506  switch( SCIPgetTypeSetppc(scip, cons) )
2507  {
2509  lhs = 1.0;
2510  rhs = 1.0;
2511  break;
2512 
2514  lhs = -SCIPinfinity(scip);
2515  rhs = 1.0;
2516  break;
2517 
2519  lhs = 1.0;
2520  rhs = SCIPinfinity(scip);
2521  break;
2522 
2523  default:
2524  SCIPerrorMessage("unexpected setppc type\n");
2525  return SCIP_ERROR;
2526  }
2527 
2528  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons),
2529  0.0, consdata->nvars, consdata->vars, coefs, NULL, lhs, rhs, SCIP_EXPRCURV_LINEAR) );
2530  assert(consdata->nlrow != NULL);
2531 
2532  SCIPfreeBufferArray(scip, &coefs);
2533  }
2534 
2535  if( !SCIPnlrowIsInNLP(consdata->nlrow) )
2536  {
2537  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
2538  }
2539 
2540  return SCIP_OKAY;
2541 }
2542 
2543 /** checks constraint for violation, and adds it as a cut if possible */
2544 static
2546  SCIP* scip, /**< SCIP data structure */
2547  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be separated */
2548  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
2549  SCIP_Bool lpfeas, /**< is the given solution feasible for the current LP ? */
2550  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2551  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
2552  SCIP_Bool* reduceddom /**< pointer to store TRUE, if a domain reduction was found */
2553  )
2554 {
2555  SCIP_CONSDATA* consdata;
2556  SCIP_Bool addcut;
2557  SCIP_Bool mustcheck;
2558 
2559  assert(cons != NULL);
2560  assert(SCIPconsGetHdlr(cons) != NULL);
2561  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2562  assert(cutoff != NULL);
2563  assert(separated != NULL);
2564  assert(reduceddom != NULL);
2565 
2566  *cutoff = FALSE;
2567 
2568  consdata = SCIPconsGetData(cons);
2569  assert(consdata != NULL);
2570  assert(consdata->nvars == 0 || consdata->vars != NULL);
2571  assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
2572  assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
2573 
2574  /* skip constraints already in the LP */
2575  if( lpfeas && consdata->row != NULL && SCIProwIsInLP(consdata->row) )
2576  return SCIP_OKAY;
2577 
2578  SCIPdebugMsg(scip, "separating constraint <%s>\n", SCIPconsGetName(cons));
2579 
2580  /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
2581  if( lpfeas )
2582  {
2583  int nfixedvars = 0;
2584 
2585  SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) );
2586 
2587  *reduceddom = (nfixedvars > 0);
2588  }
2589  else
2590  {
2591  mustcheck = TRUE;
2592  addcut = FALSE;
2593  }
2594 
2595  if( mustcheck )
2596  {
2597  assert(!addcut);
2598 
2599  /* variable's fixings didn't give us any information -> we have to check the constraint */
2600  if( lpfeas && consdata->row != NULL )
2601  {
2602  SCIP_Real feasibility;
2603 
2604  assert(!SCIProwIsInLP(consdata->row));
2605  feasibility = SCIPgetRowSolFeasibility(scip, consdata->row, sol);
2606  addcut = SCIPisFeasNegative(scip, feasibility);
2607  }
2608  else
2609  addcut = !checkCons(scip, consdata, sol);
2610 
2611  if( !addcut )
2612  {
2613  /* constraint was feasible -> increase age */
2614  SCIP_CALL( SCIPincConsAge(scip, cons) );
2615  }
2616  }
2617 
2618  if( addcut )
2619  {
2620  /* insert LP row as cut */
2621  SCIP_CALL( addCut(scip, cons, cutoff) );
2622  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2623  *separated = TRUE;
2624  }
2625 
2626  return SCIP_OKAY;
2627 }
2628 
2629 /** enforces the pseudo solution on the given constraint */
2630 static
2632  SCIP* scip, /**< SCIP data structure */
2633  SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be separated */
2634  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2635  SCIP_Bool* infeasible, /**< pointer to store TRUE, if the constraint was infeasible */
2636  SCIP_Bool* reduceddom, /**< pointer to store TRUE, if a domain reduction was found */
2637  SCIP_Bool* solvelp /**< pointer to store TRUE, if the LP has to be solved */
2638  )
2640  SCIP_Bool addcut;
2641  SCIP_Bool mustcheck;
2642  int nfixedvars = 0;
2643 
2644  assert(!SCIPhasCurrentNodeLP(scip));
2645  assert(cons != NULL);
2646  assert(SCIPconsGetHdlr(cons) != NULL);
2647  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2648  assert(cutoff != NULL);
2649  assert(infeasible != NULL);
2650  assert(reduceddom != NULL);
2651  assert(solvelp != NULL);
2652 
2653  /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
2654  SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) );
2655 
2656  *reduceddom = (nfixedvars > 0);
2657 
2658  if( mustcheck )
2659  {
2660  SCIP_CONSDATA* consdata;
2661 
2662  assert(!addcut);
2663 
2664  consdata = SCIPconsGetData(cons);
2665  assert(consdata != NULL);
2666 
2667  if( checkCons(scip, consdata, NULL) )
2668  {
2669  /* constraint was feasible -> increase age */
2670  SCIP_CALL( SCIPincConsAge(scip, cons) );
2671  }
2672  else
2673  {
2674  /* constraint was infeasible -> reset age */
2675  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2676  *infeasible = TRUE;
2677  }
2678  }
2679 
2680  if( addcut )
2681  {
2682  /* a cut must be added to the LP -> we have to solve the LP immediately */
2683  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2684  *solvelp = TRUE;
2685  }
2686 
2687  return SCIP_OKAY;
2688 }
2689 
2690 /** gets the key of the given element */
2691 static
2692 SCIP_DECL_HASHGETKEY(hashGetKeySetppccons)
2693 { /*lint --e{715}*/
2694  /* the key is the element itself */
2695  return elem;
2696 }
2697 
2698 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */
2699 static
2700 SCIP_DECL_HASHKEYEQ(hashKeyEqSetppccons)
2701 {
2702 #ifndef NDEBUG
2703  SCIP* scip;
2704 #endif
2705  SCIP_CONSDATA* consdata1;
2706  SCIP_CONSDATA* consdata2;
2707  SCIP_Bool coefsequal;
2708  int i;
2709 
2710  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
2711  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
2712  assert(consdata1->sorted);
2713  assert(consdata2->sorted);
2714 #ifndef NDEBUG
2715  scip = (SCIP*)userptr;
2716  assert(scip != NULL);
2717 #endif
2718 
2719  /* checks trivial case */
2720  if( consdata1->nvars != consdata2->nvars )
2721  return FALSE;
2722 
2723  coefsequal = TRUE;
2724 
2725  for( i = 0; i < consdata1->nvars; ++i )
2726  {
2727  /* tests if variables are equal */
2728  if( consdata1->vars[i] != consdata2->vars[i] )
2729  {
2730  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
2731  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
2732  coefsequal = FALSE;
2733  break;
2734  }
2735  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
2736  }
2737 
2738  return coefsequal;
2739 }
2740 
2741 /** returns the hash value of the key */
2742 static
2743 SCIP_DECL_HASHKEYVAL(hashKeyValSetppccons)
2744 {
2745  SCIP_CONSDATA* consdata;
2746  int minidx;
2747  int mididx;
2748  int maxidx;
2749 #ifndef NDEBUG
2750  SCIP* scip;
2752  scip = (SCIP*)userptr;
2753  assert(scip != NULL);
2754 #endif
2755 
2756  consdata = SCIPconsGetData((SCIP_CONS*)key);
2757  assert(consdata != NULL);
2758  assert(consdata->nvars > 0);
2759 
2760  /* sorts the constraints */
2761  consdataSort(consdata);
2762 
2763  minidx = SCIPvarGetIndex(consdata->vars[0]);
2764  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
2765  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
2766  assert(minidx >= 0 && minidx <= maxidx);
2767 
2768  return SCIPhashFour(consdata->nvars, minidx, mididx, maxidx);
2769 }
2770 
2771 /** add extra clique-constraints resulting from a given cliquepartition to SCIP */
2772 static
2774  SCIP*const scip, /**< SCIP data structure */
2775  SCIP_VAR**const binvars, /**< binary variables to create clique constraints */
2776  int const nbinvars, /**< number of binary variables to create clique constraints */
2777  int*const cliquepartition, /**< clique partition of binary variables */
2778  int const ncliques, /**< number of cliques in cliquepartition */
2779  SCIP_CONS**const usefulconss, /**< storage for created constraints */
2780  int*const nusefulconss, /**< pointer to store number of useful created constraints */
2781  int const nrounds, /**< actual presolving round */
2782  int*const nfixedvars, /**< pointer to count number of deleted variables */
2783  int*const naddconss, /**< pointer to count number of added constraints */
2784  int*const ndelconss, /**< pointer to count number of deleted constraints */
2785  int*const nchgcoefs, /**< pointer to count number of deleted coefficients */
2786  SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
2787  )
2788 {
2789  SCIP_CONS* cliquecons;
2790  char name[SCIP_MAXSTRLEN];
2791  int lastclqidx;
2792  int nadded;
2793  int c;
2794  int v;
2795 
2796  assert(scip != NULL);
2797  assert(binvars != NULL || nbinvars == 0);
2798  assert(cliquepartition != NULL || nbinvars == 0);
2799  assert(ncliques >= 0 && ncliques <= nbinvars);
2800  assert(usefulconss != NULL);
2801  assert(nusefulconss != NULL);
2802  assert(nfixedvars != NULL);
2803  assert(naddconss != NULL);
2804  assert(ndelconss != NULL);
2805  assert(nchgcoefs != NULL);
2806  assert(cutoff != NULL);
2807 
2808  /* no given binary variables */
2809  if( nbinvars == 0 || ncliques == 0 )
2810  return SCIP_OKAY;
2811 
2812  assert(binvars != NULL);
2813  assert(cliquepartition != NULL);
2814 
2815  /* no useful clique information */
2816  if( ncliques == nbinvars )
2817  return SCIP_OKAY;
2818 
2819  lastclqidx = 0;
2820 
2821  /* @todo: maybe sort cliques and accordingly the variables so it will be faster to add the constraints */
2822  for( c = 0; c < ncliques - 1; ++c )
2823  {
2824  if( lastclqidx >= cliquepartition[c] )
2825  continue;
2826 
2827  nadded = 0;
2828 
2829  /* name the clique constraint */
2830  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "extra_clq_%d_round_%d", cliquepartition[c], nrounds);
2831  SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, 0, NULL,
2833 
2834  /* add variables to clique constraint */
2835  for( v = c; v < nbinvars - 1; ++v )
2836  {
2837  if( cliquepartition[c] == cliquepartition[v] )
2838  {
2839  SCIP_CALL( addCoef(scip, cliquecons, binvars[v]) );
2840  ++nadded;
2841  }
2842  }
2843 
2844  /* @todo: try to find a good value for what are enough variables to create this constraint, maybe at least
2845  * (nmaxvars(over all conss)-nminvars(over all conss))/2 */
2846  if( nadded >= 2 )
2847  {
2848  SCIP_CONSDATA* cliqueconsdata;
2849 
2850  SCIPdebugMsg(scip, " -> adding clique constraint: ");
2851  SCIPdebugPrintCons(scip, cliquecons, NULL);
2852  SCIP_CALL( SCIPaddCons(scip, cliquecons) );
2853  ++(*naddconss);
2854 
2855  /* we only want to consider merged constraints */
2856  SCIP_CALL( mergeMultiples(scip, cliquecons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
2857  if( *cutoff )
2858  {
2859  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2860 
2861  return SCIP_OKAY;
2862  }
2863 
2864  cliqueconsdata = SCIPconsGetData(cliquecons);
2865  assert(cliqueconsdata != NULL);
2866 
2867  /* the artificial constraints could be deleted while merging */
2868  if( !SCIPconsIsDeleted(cliquecons) && nadded - cliqueconsdata->nfixedzeros >= 2 )
2869  {
2870  assert(cliqueconsdata->nfixedones == 0);
2871 
2872  /* save the type and constraint */
2873  usefulconss[*nusefulconss] = cliquecons;
2874  ++(*nusefulconss);
2875  }
2876  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2877  }
2878  else
2879  {
2880  SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2881  }
2882  lastclqidx = cliquepartition[c];
2883  }
2884 
2885  return SCIP_OKAY;
2886 }
2887 
2888 
2889 /** start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these
2890  * constraints
2891  */
2892 static
2894  SCIP*const scip, /**< SCIP data structure */
2895  SCIP_CONS**const conss, /**< constraint set */
2896  int const nconss, /**< number of constraints in constraint set */
2897  SCIP_CONS**const usefulconss, /**< storage for created constraints */
2898  int*const nusefulconss, /**< pointer to store number of useful created constraints */
2899  int*const nfixedvars, /**< pointer to count number of deleted variables */
2900  int*const ndelconss, /**< pointer to count number of deleted constraints */
2901  int*const nchgcoefs, /**< pointer to count number of deleted coefficients */
2902  SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
2903  )
2904 {
2905  SCIP_CONS* cons;
2906  SCIP_CONSDATA* consdata;
2907  SCIP_Bool addcut;
2908  SCIP_Bool mustcheck;
2909  int nlocaladdconss = 0;
2910  int c;
2911 
2912  assert(scip != NULL);
2913  assert(conss != NULL || nconss == 0);
2914  assert(usefulconss != NULL);
2915  assert(nusefulconss != NULL);
2916  assert(nfixedvars != NULL);
2917  assert(ndelconss != NULL);
2918  assert(nchgcoefs != NULL);
2919  assert(cutoff != NULL);
2920 
2921  if( nconss == 0 )
2922  return SCIP_OKAY;
2923 
2924  assert(conss != NULL);
2925 
2926  for( c = nconss - 1; c >= 0; --c )
2927  {
2928  cons = conss[c];
2929 
2930  /* we only want to consider constraints with either active or negated of active variables, applyfixings removes
2931  * aggregated and fixed variables to zero, processFixings removes fixings to one but no aggregation
2932  *
2933  * @todo: maybe write a new method for deleting aggregations and all fixings
2934  */
2935  SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
2936  if( *cutoff )
2937  return SCIP_OKAY;
2938 
2939  if( SCIPconsIsDeleted(cons) )
2940  {
2941  /* reset nlocaladdconss and continue */
2942  nlocaladdconss = 0;
2943  continue;
2944  }
2945  assert(nlocaladdconss == 0);
2946 
2947  SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) );
2948  if( *cutoff )
2949  return SCIP_OKAY;
2950 
2951  consdata = SCIPconsGetData(cons);
2952  assert(consdata != NULL);
2953 
2954  /* we only want to consider merged constraints */
2955  SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
2956  if( *cutoff )
2957  return SCIP_OKAY;
2958 
2959  if( SCIPconsIsModifiable(cons) || !SCIPconsIsActive(cons) )
2960  continue;
2961 
2962  assert(consdata->nfixedones == 0);
2963 
2964  if( consdata->nvars == 0 )
2965  continue;
2966 
2967  /* @todo: check for covering constraints with only two variables which are equal to a packing constraint with
2968  * negated variables */
2969  if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2970  {
2971  assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2972 
2973  usefulconss[*nusefulconss] = cons;
2974  ++(*nusefulconss);
2975  }
2976  }
2977 
2978  return SCIP_OKAY; /*lint !e438*/
2979 }
2980 
2981 /** creating all necessary data in array structure, collect all clique constraint variables and occurrences,
2982  * @note works only with merged and active not set-covering constraints
2983  */
2984 static
2986  SCIP*const scip, /**< SCIP data structure */
2987  SCIP_CONS**const usefulconss, /**< clique constraints */
2988  int const nusefulconss, /**< number of clique constraints */
2989  SCIP_VAR**const usefulvars, /**< storage for all found variables */
2990  int*const nusefulvars, /**< pointer to store number of added variables */
2991  SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
2992  int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
2993  int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */
2994  int**const varconsidxs, /**< storage for constraint indices in which the corresponding variable exists */
2995  int*const maxnvars /**< pointer to store maximal number of variables of a constraint */
2996  )
2997 {
2998  SCIP_CONS* cons;
2999  SCIP_CONSDATA* consdata;
3000  int varindex;
3001  int c;
3002  int v;
3003 
3004  assert(scip != NULL);
3005  assert(usefulconss != NULL || nusefulconss == 0);
3006  assert(usefulvars != NULL);
3007  assert(nusefulvars != NULL);
3008  assert(vartoindex != NULL);
3009  assert(varnconss != NULL);
3010  assert(maxnvarconsidx != NULL);
3011  assert(varconsidxs != NULL);
3012  assert(maxnvars != NULL);
3013 
3014  if( nusefulconss == 0 )
3015  return SCIP_OKAY;
3016 
3017  assert(usefulconss != NULL);
3018 
3019  for( c = nusefulconss - 1; c >= 0; --c )
3020  {
3021  cons = usefulconss[c];
3022 
3023  assert(SCIPconsIsActive(cons));
3024 
3025  consdata = SCIPconsGetData(cons);
3026  assert(consdata != NULL);
3027 
3028  /* here we should have no covering constraints anymore and the constraint data should be merged */
3029  assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
3030  assert(consdata->merged);
3031 
3032  /* save maximal number of vars */
3033  if( consdata->nvars > *maxnvars )
3034  *maxnvars = consdata->nvars;
3035 
3036  /* adding variables and information about occurrences to local data structure */
3037  for( v = consdata->nvars - 1; v >= 0; --v )
3038  {
3039  SCIP_VAR* var;
3040 
3041  var = consdata->vars[v];
3042  assert(var != NULL);
3043 
3044  /* don't remember fixed vars */
3045  if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
3046  continue;
3047 
3048  /* only collect active or negated active variables */
3050 
3051  if( !SCIPhashmapExists(vartoindex, (void*) var) )
3052  {
3053  SCIP_VAR* tmpvar;
3054 
3055  usefulvars[*nusefulvars] = var;
3056  ++(*nusefulvars);
3057  varindex = *nusefulvars;
3058  SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, varindex) );
3059 
3060  /* get the maximal number of occurrences of this variable, if this variables */
3061  tmpvar = SCIPvarIsNegated(var) ? SCIPvarGetNegatedVar(var) : var;
3062  maxnvarconsidx[varindex] = SCIPvarGetNLocksDownType(tmpvar, SCIP_LOCKTYPE_MODEL)
3064  SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3065  }
3066  else
3067  {
3068  assert(SCIPhashmapExists(vartoindex, (void*) var));
3069  varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var);
3070  }
3071 
3072  /* the number of occurrences of a variable is not limited by the locks (so maybe we have to increase memory),
3073  * because for examples converted cuts are not check and therefore they have no locks on their variables */
3074  if( varnconss[varindex] == maxnvarconsidx[varindex] )
3075  {
3076  maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1);
3077  SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3078  }
3079 
3080  assert(varnconss[varindex] < maxnvarconsidx[varindex]);
3081  /* add the constraint number to the variable list */
3082  varconsidxs[varindex][varnconss[varindex]] = c;
3083  /* increase number of occurrences for variables */
3084  ++(varnconss[varindex]);
3085  }
3086  } /* data structure created */
3087 
3088  return SCIP_OKAY;
3089 }
3090 
3091 /** correct clique data due to an aggregation */
3092 static
3094  SCIP_VAR*const var, /**< variable which appears less */
3095  int const considx, /**< constraint index which to remove */
3096  SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
3097  int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
3098  int**const varconsidxs /**< storage for constraint indices in which the corresponding variable exists */
3099  )
3100 {
3101  int varindex;
3102  int i;
3103 #ifndef NDEBUG
3104  SCIP_Bool found = FALSE;
3105 #endif
3106 
3107  assert(var != NULL);
3108  assert(SCIPvarGetLbLocal(var) < 0.5 && SCIPvarGetUbLocal(var) > 0.5);
3109  assert(considx >= 0);
3110  assert(vartoindex != NULL);
3111  assert(varnconss != NULL);
3112  assert(varconsidxs != NULL);
3113 
3114  assert(SCIPhashmapExists(vartoindex, (void*) var));
3115  varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var);
3116 
3117  /* remove entry of variable at the given position */
3118  for( i = 0; i < varnconss[varindex]; ++i )
3119  {
3120  if( varconsidxs[varindex][i] == considx )
3121  {
3122  varconsidxs[varindex][i] = varconsidxs[varindex][varnconss[varindex] - 1];
3123 #ifndef NDEBUG
3124  found = TRUE;
3125 #endif
3126  --(varnconss[varindex]);
3127  break;
3128  }
3129  }
3130  assert(found);
3131 }
3132 
3133 /* correct local data structure, add constraint entry to variable data */
3134 static
3136  SCIP*const scip, /**< SCIP data structure */
3137  SCIP_VAR*const addvar, /**< variable which was added */
3138  int const considx, /**< constraint index which to add */
3139  SCIP_Bool const maybenew, /**< could be a new variables, a negated of an already existing */
3140  SCIP_VAR**const usefulvars, /**< storage for all found variables */
3141  int*const nusefulvars, /**< pointer to store number of added variables */
3142  SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
3143  int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
3144  int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */
3145  int**const varconsidxs /**< storage for constraint indices in which the corresponding variable exists */
3146  )
3147 {
3148  int varindex;
3149 
3150  assert(scip != NULL);
3151  assert(addvar != NULL);
3152  assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
3153  assert(usefulvars != NULL);
3154  assert(nusefulvars != NULL);
3155  assert(vartoindex != NULL);
3156  assert(varnconss != NULL);
3157  assert(maxnvarconsidx != NULL);
3158  assert(varconsidxs != NULL);
3159 
3160  /* we add the variable to the hashmap if its new */
3161  if( maybenew && !SCIPhashmapExists(vartoindex, (void*) addvar) )
3162  {
3163  assert(SCIPvarIsActive(addvar) || SCIPvarIsNegated(addvar));
3164  assert(SCIPvarGetNegatedVar(addvar) != NULL && SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(addvar)));
3165 
3166  /* @note because we can only have created a negated variable, and we already allocated enough memory for
3167  * all (even not existing) negated variables the usefulvars array should be big enough
3168  */
3169  SCIPsortedvecInsertDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, addvar, nusefulvars, NULL);
3170  varindex = *nusefulvars;
3171  SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) addvar, varindex) );
3172 
3173  assert(varconsidxs[varindex] == NULL);
3174 
3175  maxnvarconsidx[varindex] = 1;
3176  SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3177  varnconss[varindex] = 0;
3178  }
3179  else
3180  {
3181  varindex = SCIPhashmapGetImageInt(vartoindex, (void*) addvar);
3182 
3183  /* grow the needed memory if we added a variable */
3184  if( varnconss[varindex] == maxnvarconsidx[varindex] )
3185  {
3186  maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1);
3187  SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3188  }
3189  }
3190  assert(varnconss[varindex] < maxnvarconsidx[varindex]);
3191  varconsidxs[varindex][varnconss[varindex]] = considx;
3192 
3193  /* increase number of occurrences for variables */
3194  ++(varnconss[varindex]);
3195 
3196  return SCIP_OKAY;
3197 }
3198 
3199 
3200 /** check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
3201  * possible
3202  */
3203 static
3205  SCIP*const scip, /**< SCIP data structure */
3206  SCIP_CONS*const cons, /**< constraint */
3207  SCIP_Bool const aggregate, /**< try to aggregate if possible */
3208  SCIP_VAR** undoneaggrvars, /**< array to store aggregation variables, if aggregation is not performed
3209  * yet; both variables are standing next to each other; or NULL if
3210  * aggregate == TRUE
3211  */
3212  SCIP_Bool* undoneaggrtypes, /**< array to store aggregation type, if aggregation is not performed yet;
3213  * type FALSE means the aggregation is of the form x + y = 1; type TRUE means
3214  * the aggregation is of the form x = y; or NULL if aggregate == TRUE
3215  */
3216  int*const naggregations, /**< pointer to store number of aggregations which are not yet performed;
3217  * or NULL if aggregate == TRUE
3218  */
3219  int*const saggregations, /**< pointer to store size of the array for aggregation type and two times
3220  * the value is the size of the array for the aggregation variables which
3221  * are not yet performed; or NULL if aggregate == TRUE
3222  */
3223  int*const nfixedvars, /**< pointer to count number of deleted variables */
3224  int*const naggrvars, /**< pointer to count number of aggregated variables */
3225  int*const ndelconss, /**< pointer to count number of deleted constraints */
3226  SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
3227  )
3228 {
3229  SCIP_CONSDATA* consdata;
3230  SCIP_VAR** vars;
3231  int nvars;
3232  int v;
3233  SCIP_Bool fixed;
3234 
3235  assert(scip != NULL);
3236  assert(cons != NULL);
3237  assert(nfixedvars != NULL);
3238  assert(naggrvars != NULL);
3239  assert(ndelconss != NULL);
3240  assert(cutoff != NULL);
3241 
3242  if( !SCIPconsIsActive(cons) )
3243  return SCIP_OKAY;
3244 
3245  consdata = SCIPconsGetData(cons);
3246  assert(consdata != NULL);
3247 
3248  if( consdata->presolpropagated )
3249  return SCIP_OKAY;
3250 
3251  consdata->presolpropagated = TRUE;
3252 
3253  vars = consdata->vars;
3254  nvars = consdata->nvars;
3255 
3256  /* no variables left */
3257  if( nvars == 0 && !SCIPconsIsModifiable(cons) )
3258  {
3259  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3260  {
3261  SCIPdebugMsg(scip, "empty set-partition/-covering constraint <%s> found -> cutoff\n", SCIPconsGetName(cons));
3262  *cutoff = TRUE;
3263 
3264  return SCIP_OKAY;
3265  }
3266  else
3267  {
3268  assert(consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
3269 
3270  /* delete constraint */
3271  SCIPdebugMsg(scip, " -> deleting constraint <%s>, no variables left\n", SCIPconsGetName(cons));
3272  SCIP_CALL( SCIPdelCons(scip, cons) );
3273  ++(*ndelconss);
3274 
3275  return SCIP_OKAY;
3276  }
3277  }
3278 
3279  /* more then two variables are fixed */
3280  if( consdata->nfixedones > 1 )
3281  {
3282  /* at least two variables are fixed to 1:
3283  * - a set covering constraint is feasible anyway and can be deleted
3284  * - a set partitioning or packing constraint is infeasible
3285  */
3286  if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3287  {
3288  /* delete constraint */
3289  SCIPdebugMsg(scip, " -> deleting set-covering constraint <%s>, at least two variables are fixed to 1\n", SCIPconsGetName(cons));
3290  SCIP_CALL( SCIPdelCons(scip, cons) );
3291  ++(*ndelconss);
3292 
3293  return SCIP_OKAY;
3294  }
3295 
3296  SCIPdebugMsg(scip, "set partitioning / packing constraint <%s> is infeasible, %d variables fixed to one\n", SCIPconsGetName(cons), consdata->nfixedones);
3297  *cutoff = TRUE;
3298 
3299  return SCIP_OKAY;
3300  }
3301 
3302  if( consdata->nfixedones == 1 )
3303  {
3304  /* exactly one variable is fixed to 1:
3305  * - a set covering constraint is feasible anyway and can be disabled
3306  * - all other variables in a set partitioning or packing constraint must be zero
3307  */
3308  if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING && consdata->nfixedzeros < nvars - 1 ) /*lint !e641*/
3309  {
3310  assert(vars != NULL);
3311 
3312  for( v = nvars - 1; v >= 0; --v )
3313  {
3314  if( SCIPvarGetLbLocal(vars[v]) + 0.5 < SCIPvarGetUbLocal(vars[v]) )
3315  {
3316  SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(vars[v]));
3317 
3318  /* fix all remaining variables to zero, constraint is already feasible or infeasible */
3319  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3320  if( *cutoff )
3321  {
3322  SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
3323  SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
3324 
3325  return SCIP_OKAY;
3326  }
3327 
3328  assert(fixed);
3329  ++(*nfixedvars);
3330  }
3331  }
3332  }
3333 
3334  if( !SCIPconsIsModifiable(cons) || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3335  {
3336  /* delete constraint */
3337  SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3338  assert(SCIPconsIsActive(cons));
3339  SCIP_CALL( SCIPdelCons(scip, cons) );
3340  ++(*ndelconss);
3341  }
3342 
3343  return SCIP_OKAY;
3344  }
3345 
3346  /* other propagations can only be done on not modifiable constraints */
3347  if( SCIPconsIsModifiable(cons) )
3348  return SCIP_OKAY;
3349 
3350  assert(vars != NULL);
3351 
3352  /* all variables were fixed to zero then either delete the constraint or stop with infeasibility */
3353  if( consdata->nfixedzeros == nvars )
3354  {
3355  assert(consdata->nfixedones == 0);
3356 
3357  /* all variables are fixed to zero:
3358  * - a set packing constraint is feasible anyway and can be deleted
3359  * - a set partitioning or covering constraint is infeasible, and so is the whole problem
3360  */
3361  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3362  {
3363  SCIPdebugMsg(scip, "set partitioning / covering constraint <%s> is infeasible\n", SCIPconsGetName(cons));
3364  *cutoff = TRUE;
3365 
3366  return SCIP_OKAY;
3367  }
3368 
3369  /* delete constraint */
3370  SCIPdebugMsg(scip, " -> deleting set-packing constraint <%s>, all variables are fixed to zero\n", SCIPconsGetName(cons));
3371  assert(SCIPconsIsActive(cons));
3372  SCIP_CALL( SCIPdelCons(scip, cons) );
3373  ++(*ndelconss);
3374 
3375  return SCIP_OKAY;
3376  }
3377 
3378  /* all but one variable were fixed to zero then delete the constraint and for setpartition fix the remaining variable to 1 */
3379  if( consdata->nfixedzeros + 1 == nvars )
3380  {
3381  assert(consdata->nfixedones == 0);
3382 
3383  /* all variables except one are fixed to zero:
3384  * - a set packing constraint is feasible anyway, and can be deleted
3385  * - a set partitioning or covering constraint is feasible and can be deleted after the
3386  * remaining variable is fixed to one
3387  */
3388  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3389  {
3390  fixed = FALSE;
3391  for( v = nvars - 1; v >= 0; --v )
3392  {
3393  assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
3394  if( SCIPvarGetUbLocal(vars[v]) > 0.5 )
3395  {
3396  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]));
3397 
3398  /* fix the remaining set partition variable */
3399  SCIP_CALL( SCIPfixVar(scip, vars[v], 1.0, cutoff, &fixed) );
3400  if( *cutoff )
3401  {
3402  SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 1\n",
3403  SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
3404 
3405  return SCIP_OKAY;
3406  }
3407 
3408  assert(fixed);
3409  ++(*nfixedvars);
3410  break;
3411  }
3412  }
3413  assert(fixed);
3414  }
3415 
3416  /* delete constraint */
3417  SCIPdebugMsg(scip, " -> deleting constraint <%s>, all %svariables are fixed\n", SCIPconsGetName(cons), consdata->setppctype == (int) SCIP_SETPPCTYPE_PACKING ? "but one " : "");
3418  assert(SCIPconsIsActive(cons));
3419  SCIP_CALL( SCIPdelCons(scip, cons) );
3420  ++(*ndelconss);
3421 
3422  return SCIP_OKAY;
3423  }
3424 
3425  /* all but two variable were fixed to zero in a setpartitioning constraint then delete the constraint and
3426  * aggregate the remaining two variables
3427  */
3428  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros + 2 == nvars ) /*lint !e641*/
3429  {
3430  SCIP_VAR* var;
3431 
3432  var = NULL;
3433  for( v = nvars - 1; v >= 0; --v )
3434  {
3435  assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
3436 
3437  if( SCIPvarGetUbLocal(vars[v]) > 0.5 )
3438  {
3439  if( var == NULL )
3440  var = vars[v];
3441  else
3442  {
3443  SCIP_Bool redundant;
3444  SCIP_Bool aggregated;
3445 #ifdef VARUSES
3446  SCIP_CONSHDLR* conshdlr;
3447  SCIP_CONSHDLRDATA* conshdlrdata;
3448 
3449  /* get event handler and event handler data */
3450  conshdlr = SCIPconsGetHdlr(cons);
3451  assert(conshdlr != NULL);
3452  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3453  assert(conshdlrdata != NULL);
3454 #endif
3455  if( aggregate )
3456  {
3457  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));
3458 
3459 #ifdef VARUSES
3460  /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate,
3461  * and increase usage counting again
3462  */
3463  SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var) );
3464  SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, vars[v]) );
3465 #endif
3466 
3467  /* aggregate last remaining variables in the set partitioning constraint */
3468  SCIP_CALL( SCIPaggregateVars(scip, var, vars[v], 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) );
3469  if( *cutoff )
3470  {
3471  SCIPdebugMsg(scip, "set partitioning constraint <%s>: aggregate <%s> + <%s> == 1\n",
3472  SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetName(vars[v]));
3473 
3474  return SCIP_OKAY;
3475  }
3476 
3477 #ifdef VARUSES
3478  /* increase variable usage counting again */
3479  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) );
3480  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, vars[v]) );
3481 #endif
3482 
3483  if( aggregated )
3484  ++(*naggrvars);
3485 
3486  if( redundant )
3487  {
3488  /* delete constraint */
3489  SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3490  assert(SCIPconsIsActive(cons));
3491  SCIP_CALL( SCIPdelCons(scip, cons) );
3492  ++(*ndelconss);
3493  }
3494  }
3495  else
3496  {
3497  assert(undoneaggrvars != NULL);
3498  assert(undoneaggrtypes != NULL);
3499  assert(naggregations != NULL);
3500  assert(saggregations != NULL);
3501 
3502  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));
3503 
3504  /* resize the aggregation arrays if necessary */
3505  if( *saggregations == *naggregations )
3506  {
3507  *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1);
3508  assert(*saggregations > *naggregations);
3509  SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) );
3510  SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) );
3511 
3512  /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */
3513  BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/
3514  }
3515 
3516  /* memorize aggregation variables*/
3517  assert(undoneaggrtypes[*naggregations] == FALSE);
3518  undoneaggrvars[2 * (*naggregations)] = var;
3519  undoneaggrvars[2 * (*naggregations) + 1] = vars[v];
3520  ++(*naggregations);
3521 
3522  if( !SCIPdoNotAggr(scip) )
3523  {
3524  /* delete constraint */
3525  SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3526  assert(SCIPconsIsActive(cons));
3527  SCIP_CALL( SCIPdelCons(scip, cons) );
3528  ++(*ndelconss);
3529  }
3530  }
3531 
3532  return SCIP_OKAY;
3533  }
3534  }
3535  }
3536  /* we should never be here, because the last to unfixed variables should have been either aggregated or a cutoff
3537  * should be applied
3538  */
3539  assert(FALSE); /*lint !e506*/
3540  }
3541 
3542  return SCIP_OKAY;
3543 }
3544 
3545 /** check for overlapping constraint */
3546 static
3548  SCIP*const scip, /**< SCIP data structure */
3549  SCIP_CONS*const cons, /**< constraint which may overlap */
3550  int const considx, /**< constraint index to avoid checking against itself */
3551  int const endidx, /**< end index to check against given constraint */
3552  SCIP_CONS**const usefulconss, /**< clique constraints */
3553  int const nusefulconss, /**< number of clique constraints */
3554  SCIP_VAR**const usefulvars, /**< storage for all found variables */
3555  int*const nusefulvars, /**< pointer to store number of added variables */
3556  SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
3557  int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
3558  int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */
3559  int**const varconsidxs, /**< storage for constraint indices in which the corresponding variable exists */
3560  int*const countofoverlapping, /**< the amount of variables of cons which overlap in all other constraint */
3561  SCIP_Bool const shrinking, /**< try to replace some variables with one variable */
3562  SCIP_Bool*const chgcons, /**< pointer to store if the given constraint was changed, due to
3563  * added/deleted variables
3564  */
3565  SCIP_VAR** undoneaggrvars, /**< array to store aggregation variables, if aggregation is not performed
3566  * yet; both variables are standing next to each other;
3567  */
3568  SCIP_Bool* undoneaggrtypes, /**< array to store aggregation type, if aggregation is not performed yet;
3569  * type FALSE means the aggregation is of the form x + y = 1; type TRUE means
3570  * the aggregation is of the form x = y;
3571  */
3572  int*const naggregations, /**< pointer to store number of aggregations which are not yet performed; */
3573  int*const saggregations, /**< pointer to store size of the array for aggregation type and two times
3574  * the value is the size of the array for the aggregation variables which
3575  * are not yet performed;
3576  */
3577  int*const nfixedvars, /**< pointer to count number of deleted variables */
3578  int*const naggrvars, /**< pointer to count number of aggregated variables */
3579  int*const nchgcoefs, /**< pointer to count number of changed coefficients */
3580  int*const ndelconss, /**< pointer to count number of deleted constraints */
3581  SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
3582  )
3583 {
3584  SCIP_CONS* cons1;
3585  SCIP_CONSDATA* consdata1;
3586  SCIP_CONSDATA* consdata;
3587  SCIP_VAR** vars;
3588  SCIP_VAR** vars1;
3589  SCIP_VAR* var;
3590  SCIP_VAR* var1;
3591  SCIP_Bool fixed;
3592  SCIP_Bool overlapdestroyed;
3593  int nvars;
3594  int nvars1;
3595  int oldnfixedzeros;
3596  int c;
3597  int v;
3598  int v1;
3599 #ifndef NDEBUG
3600  int oldnaggrvars;
3601 #endif
3602 
3603  assert(scip != NULL);
3604  assert(cons != NULL);
3605  assert(usefulconss != NULL && nusefulconss > 0);
3606  assert(0 <= considx && considx < nusefulconss);
3607  assert(usefulconss[considx] == cons);
3608  assert(0 <= endidx && endidx <= nusefulconss);
3609  assert(countofoverlapping != NULL);
3610  assert(chgcons != NULL);
3611  assert(undoneaggrvars != NULL);
3612  assert(undoneaggrtypes != NULL);
3613  assert(naggregations != NULL);
3614  assert(saggregations != NULL);
3615  assert(nfixedvars != NULL);
3616  assert(naggrvars != NULL);
3617  assert(nchgcoefs != NULL);
3618  assert(ndelconss != NULL);
3619  assert(cutoff != NULL);
3620 
3621  if( !SCIPconsIsActive(cons) )
3622  return SCIP_OKAY;
3623 
3624  consdata = SCIPconsGetData(cons);
3625  assert(consdata != NULL);
3626 
3627  nvars = consdata->nvars;
3628 
3629  if( nvars == 0 )
3630  return SCIP_OKAY;
3631 
3632  vars = consdata->vars;
3633  assert(vars != NULL);
3634 
3635  oldnfixedzeros = consdata->nfixedzeros;
3636  overlapdestroyed = FALSE;
3637 
3638  /* first check for redundancy for all unprocessed constraints with cons */
3639  for( c = endidx - 1; c >= 0; --c )
3640  {
3641  cons1 = usefulconss[c];
3642 
3643  if( !SCIPconsIsActive(cons1) )
3644  continue;
3645 
3646  /* avoid checking constraint against itself */
3647  if( considx == c )
3648  continue;
3649 
3650  assert(usefulconss[c] != cons);
3651 
3652 #ifndef NDEBUG
3653  oldnaggrvars = *naggrvars;
3654 #endif
3655 
3656  /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
3657  * possible
3658  */
3659  SCIP_CALL( presolvePropagateCons(scip, cons1, FALSE, undoneaggrvars, undoneaggrtypes, naggregations, saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
3660 
3661  if( *cutoff )
3662  return SCIP_OKAY;
3663 
3664  /* we can't handle aggregated variables later on so we should have saved them for later */
3665  assert(*naggrvars == oldnaggrvars);
3666 
3667  if( !SCIPconsIsActive(cons1) )
3668  continue;
3669 
3670  consdata1 = SCIPconsGetData(cons1);
3671  assert(consdata1 != NULL);
3672 
3673  nvars1 = consdata1->nvars;
3674 
3675  if( nvars1 == 0 )
3676  continue;
3677 
3678  /* no more variables from cons as nvars1 can overlap */
3679  assert(countofoverlapping[c] <= nvars1);
3680 
3681  /* constraint should not be redundant or infeasible */
3682  assert(consdata1->nfixedones == 0);
3683 
3684  SCIPdebugMsg(scip, "constraint <%s> overlaps with constraint <%s> by %d variables\n", SCIPconsGetName(cons), SCIPconsGetName(cons1), countofoverlapping[c]);
3685 
3686  /* cons1 includes cons */
3687  if( !overlapdestroyed && countofoverlapping[c] == nvars - consdata->nfixedzeros )
3688  {
3689  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
3690  {
3691  if( nvars - consdata->nfixedzeros < nvars1 )
3692  {
3693 #ifndef NDEBUG
3694  SCIP_Bool negated0;
3695  SCIP_Bool negated1;
3696 #endif
3697 
3698  /* both constraints should stay merged */
3699  assert(consdata->merged);
3700  assert(consdata1->merged);
3701 
3702  vars1 = consdata1->vars;
3703  assert(vars1 != NULL);
3704 
3705  /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3706  SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3707  /* standard setppc-sorting now lost */
3708  consdata1->sorted = FALSE;
3709 
3710  /* iterate over the both cliques variables the "same" time */
3711  for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3712  {
3713  if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3714  {
3715  --v1;
3716  continue;
3717  }
3718  if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3719  {
3720  --v;
3721  continue;
3722  }
3723 
3724  /* all variables inside the second clique constraint should be either active or negated of an active one */
3725  assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3726 
3727  /* get not negated variable and clique value in cons */
3728  if( SCIPvarGetStatus(vars[v]) != SCIP_VARSTATUS_NEGATED )
3729  {
3730  var = vars[v];
3731 #ifndef NDEBUG
3732  negated0 = FALSE;
3733 #endif
3734  }
3735  else
3736  {
3737  var = SCIPvarGetNegationVar(vars[v]);
3738 #ifndef NDEBUG
3739  negated0 = TRUE;
3740 #endif
3741  }
3742 
3743  /* get active variable and clique value of next variable */
3744  if( SCIPvarIsActive(vars1[v1]) )
3745  {
3746  var1 = vars1[v1];
3747 #ifndef NDEBUG
3748  negated1 = FALSE;
3749 #endif
3750  }
3751  else
3752  {
3754  var1 = SCIPvarGetNegationVar(vars1[v1]);
3755 #ifndef NDEBUG
3756  negated1 = TRUE;
3757 #endif
3758  }
3759 
3760  /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
3761  if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
3762  --v;
3763  /* variable index in the constraint is greater than the other one, so fix this variable */
3764  else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
3765  {
3766  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]));
3767 
3768  /* fix all variables except the one which has the negated var in the clique to zero */
3769  SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) );
3770  if( *cutoff )
3771  {
3772  SCIPdebugMsg(scip, "fixing led to cutoff\n");
3773 
3774  return SCIP_OKAY;
3775  }
3776 
3777  assert(fixed);
3778  ++(*nfixedvars);
3779  --v1;
3780  }
3781  else
3782  {
3783  /* because the constraint's are merged it is not possible that one constraint contains a negated
3784  * variable of another and because all variables in cons are in cons1 this should be really the
3785  * same variable here; so we can decrease v and v1
3786  */
3787  assert(negated0 == negated1);
3788 
3789  --v;
3790  --v1;
3791  }
3792  }
3793  /* maybe we ended because of cons(v reached -1) so try to add rest of cons1 to cons */
3794  for( ; v1 >= 0; --v1)
3795  {
3796  if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3797  continue;
3798 
3799  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]));
3800 
3801  /* fix all variables except the one which has the negated var in the clique to zero */
3802  SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) );
3803  if( *cutoff )
3804  {
3805  SCIPdebugMsg(scip, "fixing led to cutoff\n");
3806 
3807  return SCIP_OKAY;
3808  }
3809 
3810  assert(fixed);
3811  ++(*nfixedvars);
3812  }
3813  }
3814 
3815  /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was
3816  * fixed to one, it's infeasible */
3817  if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nfixedzeros == nvars1 && consdata1->nfixedones != 1 ) /*lint !e641*/
3818  {
3819  SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1));
3820  *cutoff = TRUE;
3821 
3822  return SCIP_OKAY;
3823  }
3824 
3825  assert(SCIPconsIsActive(cons1));
3826  /* delete second constraint */
3827  SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx);
3828 
3829  SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
3830  SCIP_CALL( SCIPdelCons(scip, cons1) );
3831  ++(*ndelconss);
3832  }
3833  /* could already be deleted because the constraint was included in another set partition constraint */
3834  else if( SCIPconsIsActive(cons) )
3835  {
3836  /* delete cons due to redundancy to cons1 */
3837  SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c);
3838 
3839  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) );
3840  SCIP_CALL( SCIPdelCons(scip, cons) );
3841  ++(*ndelconss);
3842  }
3843  }
3844  /* cons includes cons1
3845  *
3846  * @note that zero fixations from above can only appear through a set-partitioning constraint, this means if
3847  * cons was the set-partitioning constraint only variables which are not in this constraint could be fixed
3848  * to zero, and this also means that the overlapping variables in this particular case are still active or
3849  * fixed to 1
3850  * later on it could be possible that even variables in cons are fixed to zero, which can lead to wrong
3851  * results when checking if countofoverlapping[c] + consdata1->nfixedzeros == nvars1, because a fixed
3852  * variable could be counted twice
3853  */
3854  else if( (!overlapdestroyed && countofoverlapping[c] + consdata1->nfixedzeros == nvars1) || countofoverlapping[c] == nvars1 )
3855  {
3856  /* even in deleted constraints we may fix unfixed variables */
3857  if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
3858  {
3859  const int oldnfixedvars = *nfixedvars;
3860 #ifndef NDEBUG
3861  SCIP_Bool negated0;
3862  SCIP_Bool negated1;
3863 #endif
3864  /* both constraints should stay merged */
3865  assert(consdata->merged);
3866  assert(consdata1->merged);
3867 
3868  vars1 = consdata1->vars;
3869 
3870  /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3871  SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3872  /* standard setppc-sorting now lost */
3873  consdata1->sorted = FALSE;
3874 
3875  /* iterate over the both cliques variables the "same" time */
3876  for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3877  {
3878  if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3879  {
3880  --v1;
3881  continue;
3882  }
3883  if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3884  {
3885  --v;
3886  continue;
3887  }
3888 
3889  /* all variables inside the second clique constraint should be either active or negated of an active one */
3890  assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3891  /* all variables inside the first clique constraint should be either active or negated of an active one */
3892  assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
3893 
3894  /* get not negated variable and clique value in cons */
3895  if( SCIPvarIsActive(vars[v]) )
3896  {
3897  var = vars[v];
3898 #ifndef NDEBUG
3899  negated0 = FALSE;
3900 #endif
3901  }
3902  else
3903  {
3905  var = SCIPvarGetNegationVar(vars[v]);
3906 #ifndef NDEBUG
3907  negated0 = TRUE;
3908 #endif
3909  }
3910 
3911  /* get active variable and clique value of next variable */
3912  if( SCIPvarIsActive(vars1[v1]) )
3913  {
3914  var1 = vars1[v1];
3915 #ifndef NDEBUG
3916  negated1 = FALSE;
3917 #endif
3918  }
3919  else
3920  {
3922  var1 = SCIPvarGetNegationVar(vars1[v1]);
3923 #ifndef NDEBUG
3924  negated1 = TRUE;
3925 #endif
3926  }
3927 
3928  /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
3929  if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
3930  {
3931  SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(var));
3932 
3933  /* fix all variables except the one which has the negated var in the clique to zero */
3934  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3935  if( *cutoff )
3936  {
3937  SCIPdebugMsg(scip, "fixing led to cutoff\n");
3938 
3939  return SCIP_OKAY;
3940  }
3941 
3942  assert(fixed);
3943  ++(*nfixedvars);
3944 
3945  --v;
3946  }
3947  /* variable index in the constraint is greater than the other one, so fix this variable */
3948  else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
3949  --v1;
3950  else
3951  {
3952  /* because the constraint's are merged it is not possible that one constraint contains a negated
3953  * variable of another and because all variables in cons1 are in cons this should be really the same
3954  * variable here; so we can decrease v and v1
3955  */
3956  assert(negated0 == negated1);
3957 
3958  --v;
3959  --v1;
3960  }
3961  }
3962 
3963  /* maybe we ended because of cons1(v1 reached -1) so try to add rest of cons to cons1 */
3964  for( ; v >= 0; --v)
3965  {
3966  if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3967  continue;
3968 
3969  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]));
3970 
3971  /* fix all variables except the one which has the negated var in the clique to zero */
3972  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3973  if( *cutoff )
3974  {
3975  SCIPdebugMsg(scip, "fixing led to cutoff\n");
3976 
3977  return SCIP_OKAY;
3978  }
3979 
3980  assert(fixed);
3981  ++(*nfixedvars);
3982  }
3983 
3984  /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was
3985  * fixed to one, it's infeasible */
3986  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros == nvars && consdata->nfixedones != 1 ) /*lint !e641*/
3987  {
3988  SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1));
3989  *cutoff = TRUE;
3990 
3991  return SCIP_OKAY;
3992  }
3993 
3994  /* could already be deleted because the constraint was included in another set partition constraint */
3995  if( SCIPconsIsActive(cons) )
3996  {
3997  /* delete cons because it include another set partitioning constraint */
3998  SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c);
3999  assert(SCIPconsIsActive(cons));
4000 
4001  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) );
4002  SCIP_CALL( SCIPdelCons(scip, cons) );
4003  ++(*ndelconss);
4004  }
4005 
4006  /* due to fixings in cons0 mark overlapping invalid for checking with fixedzero variables together */
4007  if( oldnfixedvars < *nfixedvars )
4008  overlapdestroyed = TRUE;
4009  }
4010  else
4011  {
4012  assert(consdata1->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
4013 
4014  /* delete cons1 due to redundancy to cons */
4015  SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx);
4016  assert(SCIPconsIsActive(cons1));
4017 
4018  SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
4019  SCIP_CALL( SCIPdelCons(scip, cons1) );
4020  ++(*ndelconss);
4021  }
4022  }
4023  /* if cons has only one unfixed variable which is not in cons1 and cons1 has one variable which does not appear in
4024  * cons and both constraints are setpartitioning constraints we might aggregate both not overlapping variables and
4025  * delete one constraint
4026  */
4027  else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1 && countofoverlapping[c] == nvars1 - 1 ) /*lint !e641*/
4028  {
4029  SCIP_VAR* aggvar1;
4030  SCIP_VAR* aggvar2;
4031  SCIP_Bool negated0;
4032  SCIP_Bool negated1;
4033 
4034  aggvar1 = NULL;
4035  aggvar2 = NULL;
4036 
4037  /* both constraints should stay merged */
4038  assert(consdata->merged);
4039  assert(consdata1->merged);
4040 
4041  vars1 = consdata1->vars;
4042 
4043  /* sorting array after indices of variables, negated and active counterparts would stand side by side */
4044  SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
4045  /* standard setppc-sorting now lost */
4046  consdata1->sorted = FALSE;
4047 
4048  /* iterate over the both cliques variables the "same" time */
4049  for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
4050  {
4051  if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
4052  {
4053  --v1;
4054  continue;
4055  }
4056  if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
4057  {
4058  --v;
4059  continue;
4060  }
4061 
4062  /* all variables inside the second clique constraint should be either active or negated of an active one */
4063  assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
4064  /* all variables inside the first clique constraint should be either active or negated of an active one */
4065  assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
4066 
4067  /* get not negated variable and clique value in cons */
4068  if( SCIPvarIsActive(vars[v]) )
4069  {
4070  var = vars[v];
4071  negated0 = FALSE;
4072  }
4073  else
4074  {
4076  var = SCIPvarGetNegationVar(vars[v]);
4077  negated0 = TRUE;
4078  }
4079 
4080  /* get active variable and clique value of next variable */
4081  if( SCIPvarIsActive(vars1[v1]) )
4082  {
4083  var1 = vars1[v1];
4084  negated1 = FALSE;
4085  }
4086  else
4087  {
4089  var1 = SCIPvarGetNegationVar(vars1[v1]);
4090  negated1 = TRUE;
4091  }
4092 
4093  /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4094  if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
4095  {
4096  assert(aggvar1 == NULL);
4097  aggvar1 = vars[v];
4098 
4099  if( aggvar2 != NULL )
4100  break;
4101 
4102  --v;
4103  }
4104  /* variable index in the constraint is greater than the other one, so fix this variable */
4105  else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
4106  {
4107  assert(aggvar2 == NULL);
4108  aggvar2 = vars1[v1];
4109 
4110  if( aggvar1 != NULL )
4111  break;
4112 
4113  --v1;
4114  }
4115  else
4116  {
4117  /* because the constraint's are merged it is not possible that one constraint contains a negated variable
4118  * of another, but both variables in both constraints still can be negated to each other
4119  */
4120  if( negated0 != negated1 )
4121  {
4122  /* cons is except for one variable equal to cons1 and the unequal variable in cons is negated
4123  * to the one in cons1, so the problem is infeasible
4124  */
4125  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]));
4126  *cutoff = TRUE;
4127 
4128  return SCIP_OKAY;
4129  }
4130  --v;
4131  --v1;
4132  }
4133  }
4134 
4135  /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */
4136  if( aggvar1 == NULL && aggvar2 == NULL )
4137  continue;
4138 
4139  /* determine second aggregation var, if not yet done */
4140  if( aggvar2 == NULL )
4141  {
4142  for( ; v1 >= 0; --v1)
4143  {
4144  if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
4145  continue;
4146 
4147  aggvar2 = vars1[v1];
4148  break;
4149  }
4150  }
4151  /* determine first aggregation var, if not yet done */
4152  else if( aggvar1 == NULL )
4153  {
4154  /* maybe we ended because of cons1(v1 reached -1) so find the aggvar1 in cons */
4155  for( ; v >= 0; --v)
4156  {
4157  if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
4158  continue;
4159 
4160  aggvar1 = vars[v];
4161  break;
4162  }
4163  }
4164 
4165  /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */
4166  if( aggvar1 == NULL || aggvar2 == NULL )
4167  continue;
4168 
4169  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));
4170 
4171  /* resize the aggregation arrays if necessary */
4172  if( *saggregations == *naggregations )
4173  {
4174  *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1);
4175  assert(*saggregations > *naggregations);
4176  SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) );
4177  SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) );
4178 
4179  /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */
4180  BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/
4181  }
4182 
4183  /* memorize aggregation variables*/
4184  undoneaggrtypes[*naggregations] = TRUE;
4185  undoneaggrvars[2 * (*naggregations)] = aggvar1;
4186  undoneaggrvars[2 * (*naggregations) + 1] = aggvar2;
4187  ++(*naggregations);
4188 
4189  if( !SCIPdoNotAggr(scip) )
4190  {
4191  /* delete constraint */
4192  SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it is dominated by constraint <%s>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons));
4193  assert(SCIPconsIsActive(cons1));
4194 
4195  SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
4196  SCIP_CALL( SCIPdelCons(scip, cons1) );
4197  ++(*ndelconss);
4198  }
4199  }
4200  /* w.l.o.g. cons is a setpartitioning constraint and countofoverlapping == nvars - oldnfixedzeros - 1 we can
4201  * delete all overlapping variables in cons1 and add the negated variable of the not overlapped variable to cons
4202  * 1; the result should be a shorter constraint with the same impact
4203  */
4204  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*/
4205  {
4206  SCIP_CONSDATA* consdatachange;
4207  SCIP_VAR** varstostay;
4208  SCIP_VAR** varstochange;
4209  SCIP_CONS* constochange;
4210  SCIP_CONS* constostay;
4211  SCIP_VAR* addvar;
4212  SCIP_Bool negated0;
4213  SCIP_Bool negated1;
4214  int nvarstostay;
4215  int nvarstochange;
4216  int constochangeidx;
4217 #ifndef NDEBUG
4218  const int oldnchgcoefs = *nchgcoefs;
4219 #endif
4220 
4221  addvar = NULL;
4222 
4223  assert((consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING) != (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING) || countofoverlapping[c] != nvars - 1 || countofoverlapping[c] != nvars1 - 1); /*lint !e641*/
4224 
4225  /* both constraints should stay merged */
4226  assert(consdata->merged);
4227  assert(consdata1->merged);
4228 
4229  /* sorting array after indices of variables, negated and active counterparts would stand side by side */
4230  SCIPsortDownPtr((void**)(consdata1->vars), SCIPvarCompActiveAndNegated, nvars1);
4231  /* standard setppc-sorting now lost */
4232  consdata1->sorted = FALSE;
4233 
4234  /* initialize variables */
4235  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1) /*lint !e641*/
4236  {
4237  varstostay = vars;
4238  varstochange = consdata1->vars;
4239  nvarstostay = nvars;
4240  nvarstochange = nvars1;
4241  constostay = cons;
4242  constochange = cons1;
4243  consdatachange = consdata1;
4244  constochangeidx = c;
4245  }
4246  else
4247  {
4248  varstostay = consdata1->vars;
4249  varstochange = vars;
4250  nvarstostay = nvars1;
4251  nvarstochange = nvars;
4252  constostay = cons1;
4253  constochange = cons;
4254  consdatachange = consdata;
4255  constochangeidx = considx;
4256 
4257  *chgcons = TRUE;
4258  }
4259 
4260  /* iterate over the both cliques variables the "same" time, here we need the backward loop, because we
4261  * delete some variables and we don not want to loose order
4262  */
4263  for( v = nvarstostay - 1, v1 = nvarstochange - 1; v >= 0 && v1 >= 0; )
4264  {
4265  if( SCIPvarGetLbLocal(varstochange[v1]) > 0.5 || SCIPvarGetUbLocal(varstochange[v1]) < 0.5 )
4266  {
4267  --v1;
4268  continue;
4269  }
4270  if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 )
4271  {
4272  --v;
4273  continue;
4274  }
4275 
4276  /* all variables inside the second clique constraint should be either active or negated of an active one */
4277  assert(SCIPvarIsActive(varstochange[v1]) || (SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1]))));
4278  /* all variables inside the first clique constraint should be either active or negated of an active one */
4279  assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v]))));
4280 
4281  /* get not negated variable and clique value in constostay */
4282  if( SCIPvarIsActive(varstostay[v]) )
4283  {
4284  var = varstostay[v];
4285  negated0 = FALSE;
4286  }
4287  else
4288  {
4289  assert(SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v])));
4290  var = SCIPvarGetNegationVar(varstostay[v]);
4291  negated0 = TRUE;
4292  }
4293 
4294  /* get active variable and clique value of in constochange*/
4295  if( SCIPvarIsActive(varstochange[v1]) )
4296  {
4297  var1 = varstochange[v1];
4298  negated1 = FALSE;
4299  }
4300  else
4301  {
4302  assert(SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1])));
4303  var1 = SCIPvarGetNegationVar(varstochange[v1]);
4304  negated1 = TRUE;
4305  }
4306 
4307  /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4308  if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
4309  {
4310  assert(addvar == NULL);
4311  addvar = varstostay[v];
4312  --v;
4313  }
4314  /* variable index in the constraint is greater than the other one, so fix this variable */
4315  else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
4316  {
4317  --v1;
4318  }
4319  else
4320  {
4321  /* because the constraint's are merged it is not possible that one constraint contains a negated variable
4322  * of another, but both constraint might have a variable in negated form of the other
4323  */
4324  if( negated0 != negated1 )
4325  {
4326  assert(addvar == NULL);
4327 
4328  SCIPdebugMsg(scip, "-> trying to fix <%s> to 0 because it would exist twice in a constraint\n", SCIPvarGetName(varstochange[v1]));
4329 
4330  /* fix variable to zero */
4331  SCIP_CALL( SCIPfixVar(scip, varstochange[v1], 0.0, cutoff, &fixed) );
4332  if( *cutoff )
4333  {
4334  SCIPdebugMsg(scip, "fixing led to cutoff\n");
4335 
4336  return SCIP_OKAY;
4337  }
4338 
4339  assert(fixed);
4340  ++(*nfixedvars);
4341 
4342  /* the above fixing is equal to the fixation of varstostay[v] to 1, so we can call presolvePropagateCons() for consstay */
4343  SCIP_CALL( presolvePropagateCons(scip, constostay, FALSE, NULL, NULL, NULL, NULL, nfixedvars, naggrvars, ndelconss, cutoff) );
4344 
4345  return SCIP_OKAY;
4346  }
4347  else
4348  {
4349  /* correct local data structure, remove variable from constraint entry where it will be removed */
4350  deleteCliqueDataEntry(varstochange[v1], constochangeidx, vartoindex, varnconss, varconsidxs);
4351 
4352  SCIPdebugMsg(scip, " -> deleting variable <%s> in constraint <%s> number %d, because it will be replaced\n", SCIPvarGetName(varstochange[v1]), SCIPconsGetName(constochange), constochangeidx);
4353  /* delete overlapping variables in constochange */
4354  SCIP_CALL( delCoefPos(scip, constochange, v1) );
4355  ++(*nchgcoefs);
4356  }
4357 
4358  --v;
4359  --v1;
4360  }
4361  }
4362  assert(addvar != NULL || v >= 0);
4363  /* we should have removed exactly countofoverlapping[c] variables from the constochange */
4364  assert(*nchgcoefs - oldnchgcoefs == countofoverlapping[c]);
4365 
4366  /* determine addvar if not yet found */
4367  if( addvar == NULL )
4368  {
4369  for( ; v >= 0; --v)
4370  {
4371  if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 )
4372  continue;
4373 
4374  /* all variables inside the first clique constraint should be either active or negated of an active one */
4375  assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v]))));
4376 
4377  addvar = varstostay[v];
4378  break;
4379  }
4380  }
4381  assert(addvar != NULL);
4382 
4383  /* get representative variable for all deleted variables */
4384  SCIP_CALL( SCIPgetNegatedVar(scip, addvar, &addvar) );
4385  assert(addvar != NULL);
4386 
4387  SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(constochange), constochangeidx);
4388  /* add representative for overlapping instead */
4389  SCIP_CALL( addCoef(scip, constochange, addvar) );
4390  ++(*nchgcoefs);
4391 
4392  /* constraint should be still merged because this added variable is new in this constraint */
4393  consdatachange->merged = TRUE;
4394  assert(constochangeidx == (cons == constochange ? considx : c));
4395 
4396  /* correct local data structure, add constraint entry to variable data */
4397  SCIP_CALL( addCliqueDataEntry(scip, addvar, constochangeidx, TRUE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4398 
4399  /* cons changed so much, that it cannot be used for more overlapping checks */
4400  if( *chgcons )
4401  return SCIP_OKAY;
4402  }
4403  }
4404 
4405  return SCIP_OKAY;
4406 }
4407 
4408 /** try to lift variables to given constraint */
4409 /** @todo try another variant by determine lifting variables as the intersection of all cliques variables of the
4410  * constraint variables, note that the intersection changes after one variable was added
4411  */
4412 static
4414  SCIP*const scip, /**< SCIP data structure */
4415  SCIP_CONS*const cons, /**< constraint which may overlap */
4416  int const arraypos, /**< position of constraint in global array */
4417  SCIP_VAR**const usefulvars, /**< possible variables to lift */
4418  int*const nusefulvars, /**< pointer to store number of added variables */
4419  int const endidx, /**< end index for possible lifting variables */
4420  SCIP_Bool** cliquevalues, /**< pointer to clique values of constraint-variables, either one if the
4421  * variable is active or zero if the variable is negated
4422  * @note this array can be resized in this method
4423  */
4424  SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
4425  int*const varnconss, /**< array with number of constraints a variable occurs */
4426  int*const maxnvarconsidx, /**< array with the maximal number of occurrences of a variable */
4427  int**const varconsidxs, /**< array with constraint indices in which the corresponding variable
4428  * exists
4429  */
4430  int*const maxnvars, /**< pointer to store maximal number of variables of a constraint */
4431  int*const nadded, /**< pointer to store number of possible added variables */
4432  SCIP_Bool*const chgcons, /**< pointer to store if the constraint was changed, due to added
4433  * variables
4434  */
4435  int*const nfixedvars, /**< pointer to count number of deleted variables */
4436  int*const ndelconss, /**< pointer to count number of deleted constraints */
4437  SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
4438  )
4439 {
4440  SCIP_CONSDATA* consdata;
4441  SCIP_VAR** vars;
4442  SCIP_VAR* var;
4443  SCIP_VAR* var1;
4444  SCIP_Bool fixed;
4445  SCIP_Bool value;
4446  int nvars;
4447  int nottocheck; /* will be the position for a variable in cons0 which is in negated form in the same clique */
4448  int v;
4449  int v1;
4450  int k;
4451 
4452  assert(scip != NULL);
4453  assert(cons != NULL);
4454  assert(usefulvars != NULL);
4455  assert(cliquevalues != NULL);
4456  assert(*cliquevalues != NULL);
4457  assert(vartoindex != NULL);
4458  assert(varnconss != NULL);
4459  assert(maxnvarconsidx != NULL);
4460  assert(varconsidxs != NULL);
4461  assert(maxnvars != NULL);
4462  assert(nadded != NULL);
4463  assert(chgcons != NULL);
4464  assert(nfixedvars != NULL);
4465  assert(ndelconss != NULL);
4466  assert(cutoff != NULL);
4467 
4468  if( !SCIPconsIsActive(cons) )
4469  return SCIP_OKAY;
4470 
4471  consdata = SCIPconsGetData(cons);
4472  assert(consdata != NULL);
4473 
4474  nvars = consdata->nvars;
4475 
4476  if( nvars == 0 )
4477  return SCIP_OKAY;
4478 
4479  assert(nvars <= *maxnvars);
4480 
4481  vars = consdata->vars;
4482  assert(vars != NULL);
4483 
4484  v1 = endidx;
4485 
4486  /* now we try to add variables with index prior to endidx to cons */
4487  for( v = nvars - 1; v >= 0 && v1 >= 0; )
4488  {
4489  if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 )
4490  {
4491  --v1;
4492  continue;
4493  }
4494  if( SCIPvarGetUbLocal(vars[v]) < 0.5 )
4495  {
4496  --v;
4497  continue;
4498  }
4499 
4500  /* check that constraint variables are still correctly sorted, indices of active variables should be decreasing */
4501  assert(v == 0 || SCIPvarCompareActiveAndNegated(vars[v], vars[v - 1]) <= 0);
4502 
4503  /* there should no variables fixed to one occur in our constraint */
4504  assert(SCIPvarGetLbLocal(vars[v]) < 0.5 && SCIPvarGetUbLocal(vars[v]) > 0.5);
4505  assert(SCIPvarGetLbLocal(usefulvars[v1]) < 0.5 && SCIPvarGetUbLocal(usefulvars[v1]) > 0.5);
4506 
4507  /* all variables which we have inside the clique constraint and which can possibly be added should be either active or negated */
4508  assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
4509  assert(SCIPvarIsActive(usefulvars[v1]) || (SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1]))));
4510 
4511  /* constraint should during adding of variables stay merged, because for each variable which is added holds that
4512  * the index of this corresponding active variable is pairwise different to all indices of all active
4513  * corresponding variables inside the constraint
4514  * @note it should not happen that we add one variable and the corresponding counterpart to the same constraint */
4515  assert(consdata->merged);
4516 
4517  /* get active variable and clique value in cons */
4518  if( (*cliquevalues)[v] )
4519  var = vars[v];
4520  else
4521  {
4523  var = SCIPvarGetNegationVar(vars[v]);
4524  }
4525 
4526  /* get active variable and clique value of next variable */
4527  if( SCIPvarIsActive(usefulvars[v1]) )
4528  {
4529  var1 = usefulvars[v1];
4530  value = TRUE;
4531  }
4532  else
4533  {
4534  assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1])));
4535  var1 = SCIPvarGetNegationVar(usefulvars[v1]);
4536  value = FALSE;
4537  }
4538 
4539  nottocheck = -1;
4540  k = 0;
4541 
4542  /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4543  if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
4544  {
4545  --v;
4546  continue;
4547  }
4548  /* variable index in the constraint is greater than the other one, so check for possible inclusion of the variable */
4549  else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
4550  {
4551  assert(consdata == SCIPconsGetData(cons));
4552 
4553  /* check if every variable in the actual clique is in clique with the new variable */
4554  for( k = nvars - 1; k >= 0; --k )
4555  {
4556  if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4557  {
4558  /* there should no variables fixed to one occur in our constraint */
4559  assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4560  assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4561 
4562  if( (*cliquevalues)[k] )
4563  {
4564  assert(SCIPvarIsActive(vars[k]));
4565  var = vars[k];
4566  }
4567  else
4568  {
4570  var = SCIPvarGetNegationVar(vars[k]);
4571  }
4572  if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) )
4573  break;
4574  }
4575  }
4576  --v1;
4577  }
4578  /* variable index in the constraint is equal to the index of the other variable, check if these variables are
4579  * negated of each other so memorize the position and check for possible inclusion of the new variable and if
4580  * possible decrease indices
4581  */
4582  else
4583  {
4584  /* one clique contains the negated and the other clique the corresponding active var */
4585  if( value != (*cliquevalues)[v] )
4586  {
4587  nottocheck = v;
4588 
4589  assert(consdata == SCIPconsGetData(cons));
4590  assert(nvars <= consdata->nvars);
4591 
4592  /* check if every variable in the actual clique is in clique with the new variable */
4593  for( k = nvars - 1; k >= 0; --k )
4594  {
4595  if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4596  {
4597  /* there should no variables fixed to one occur in our constraint */
4598  assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4599 
4600  assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4601 
4602  if( k == nottocheck )
4603  continue;
4604 
4605  if( (*cliquevalues)[k] )
4606  {
4607  assert(SCIPvarIsActive(vars[k]));
4608  var = vars[k];
4609  }
4610  else
4611  {
4613  var = SCIPvarGetNegationVar(vars[k]);
4614  }
4615 
4616  if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) )
4617  break;
4618  }
4619  }
4620  }
4621  /* don't decrease v because it might happen that the corresponding negated variable of var is next in
4622  * usefulvars
4623  */
4624  --v1;
4625  }
4626 
4627  /* if k is smaller than 0 than the possible new variables is in the same clique with all variables of cons,
4628  * so we add the new variable to clique constraint or fix some variables */
4629  if( k < 0 )
4630  {
4631  ++(*nadded);
4632 
4633  /* we found a variable which is the negated variable of another one in this clique so we can fix all
4634  * other variable to zero and if it's a partitioning constraint we can also fix the variable of the
4635  * negated to one and we can delete the constraint too */
4636  if( nottocheck >= 0 )
4637  {
4638  assert(consdata == SCIPconsGetData(cons));
4639  assert(nvars <= consdata->nvars);
4640  assert(consdata->merged);
4641 
4642  /* process all vars for possible fixing */
4643  for( k = consdata->nvars - 1; k >= 0; --k )
4644  {
4645  if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4646  {
4647  /* there should no variables fixed to one occur in our constraint */
4648  assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
4649 
4650  assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4651 
4652  if( k != nottocheck )
4653  {
4654  SCIPdebugMsg(scip, "trying to fix <%s> to 0 because we could lift a negated variable of another constraint variable\n", SCIPvarGetName(vars[k]));
4655  /* fix variable to zero */
4656  SCIP_CALL( SCIPfixVar(scip, vars[k], 0.0, cutoff, &fixed) );
4657 
4658  if( *cutoff )
4659  {
4660  SCIPdebugMsg(scip, "fixing led to cutoff\n");
4661 
4662  return SCIP_OKAY;
4663  }
4664 
4665  assert(fixed);
4666 
4667  ++(*nfixedvars);
4668  }
4669  }
4670  }
4671  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4672  {
4673  assert(SCIPvarIsActive(vars[nottocheck]) || (SCIPvarGetStatus(vars[nottocheck]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[nottocheck]))));
4674 
4675  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]));
4676  /* fix the remaining variable to one, due to it's the only one left to satisfy the constraint */
4677  SCIP_CALL( SCIPfixVar(scip, vars[nottocheck], 1.0, cutoff, &fixed) );
4678  if( *cutoff )
4679  {
4680  SCIPdebugMsg(scip, "fixing led to cutoff\n");
4681 
4682  return SCIP_OKAY;
4683  }
4684 
4685  assert(fixed);
4686  ++(*nfixedvars);
4687  }
4688 
4689  /* delete constraint */
4690  SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to active and negated variable in the same clique constraint\n", SCIPconsGetName(cons), arraypos);
4691  assert(SCIPconsIsActive(cons));
4692  SCIP_CALL( SCIPdelCons(scip, cons) );
4693  ++(*ndelconss);
4694 
4695  break;
4696  }
4697  /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */
4698  else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4699  {
4700  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]));
4701  /* fix variable to zero */
4702  SCIP_CALL( SCIPfixVar(scip, usefulvars[v1 + 1], 0.0, cutoff, &fixed) );
4703 
4704  if( *cutoff )
4705  {
4706  SCIPdebugMsg(scip, "fixing led to cutoff\n");
4707 
4708  return SCIP_OKAY;
4709  }
4710 
4711  assert(fixed);
4712 
4713  ++(*nfixedvars);
4714  }
4715  /* we have found a new variable for a set packing constraint cons, so add the found variable to the first constraint */
4716  else
4717  {
4718  SCIP_VAR* addvar;
4719 
4720  assert(SCIPconsIsActive(cons));
4721 
4722  addvar = usefulvars[v1 + 1];
4723 
4724  assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
4725 
4726  /* add representative instead */
4727  SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(usefulvars[v1 + 1]), SCIPconsGetName(cons), arraypos);
4728  SCIP_CALL( addCoef(scip, cons, addvar) );
4729  assert(consdata == SCIPconsGetData(cons));
4730  /* we know that this constraint stays merged but later on we have to resort */
4731  consdata->merged = TRUE;
4732 
4733  /* second we add the constraint index to the list of indices where this variable occurs */
4734  assert(SCIPhashmapExists(vartoindex, (void*) addvar));
4735 
4736  /* correct local data structure, add constraint entry to variable data */
4737  SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4738 
4739  /* we need the new pointer to the variables, because due to adding variables it is possible that we
4740  * did reallocate the variables array inside the constraint, the index v should stay the same because the
4741  * added variable was inserted at the end and we are decreasing v in our for loop
4742  */
4743  vars = consdata->vars;
4744  nvars = consdata->nvars;
4745 
4746  /* we need to update our data structure */
4747 
4748  /* resize clique array if necessary, due to adding variables */
4749  if( (*maxnvars) < nvars )
4750  {
4751  while( (*maxnvars) < nvars )
4752  (*maxnvars) *= 2 ;
4753  SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) );
4754  }
4755  (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE;
4756 
4757  (*chgcons) = TRUE;
4758  }
4759  }
4760  }
4761 
4762  if( !SCIPconsIsActive(cons) )
4763  return SCIP_OKAY;
4764 
4765  /* maybe we stopped because of cons(v reached -1) so try to add rest in usefulvars */
4766  for( ; v1 >= 0; --v1)
4767  {
4768  if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 )
4769  continue;
4770 
4771  /* get active variable and clique value */
4772  if( SCIPvarIsActive(usefulvars[v1]) )
4773  {
4774  var1 = usefulvars[v1];
4775  value = TRUE;
4776  }
4777  else
4778  {
4779  assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1])));
4780  var1 = SCIPvarGetNegationVar(usefulvars[v1]);
4781  value = FALSE;
4782  }
4783 
4784  assert(consdata == SCIPconsGetData(cons));
4785  assert(nvars <= consdata->nvars);
4786 
4787  /* check if every variable in the actual clique is in clique with the new variable */
4788  for( k = nvars - 1; k >= 0; --k )
4789  {
4790  if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4791  {
4792  /* there should no variables fixed to one occur in our constraint */
4793  assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4794 
4795  assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4796 
4797  if( (*cliquevalues)[k] )
4798  {
4799  assert(SCIPvarIsActive(vars[k]));
4800  var = vars[k];
4801  }
4802  else
4803  {
4805  var = SCIPvarGetNegationVar(vars[k]);
4806  }
4807 
4808  if( !SCIPvarsHaveCommonClique(var1, value, var, (*cliquevalues)[k], TRUE) )
4809  break;
4810  }
4811  }
4812 
4813  /* add new variable to clique constraint or fix some variables */
4814  if( k < 0 )
4815  {
4816  /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */
4817  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4818  {
4819  SCIPdebugMsg(scip, "trying to fix <%s> to 0 because this variable is in the same clique with a set partition\n", SCIPvarGetName(usefulvars[v1]));
4820 
4821  /* fix variable to zero */
4822  SCIP_CALL( SCIPfixVar(scip, usefulvars[v1], 0.0, cutoff, &fixed) );
4823  if( *cutoff )
4824  {
4825  SCIPdebugMsg(scip, "fixing led to cutoff\n");
4826 
4827  return SCIP_OKAY;
4828  }
4829  assert(fixed);
4830 
4831  ++(*nfixedvars);
4832  ++(*nadded);
4833  }
4834  /* add the found variable to the first constraint */
4835  else
4836  {
4837  SCIP_VAR* addvar;
4838 
4839  assert(SCIPconsIsActive(cons));
4840 
4841  addvar = usefulvars[v1];
4842 
4843  assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
4844 
4845  /* add representative instead */
4846  SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(cons), arraypos);
4847  SCIP_CALL( addCoef(scip, cons, addvar) );
4848  assert(consdata == SCIPconsGetData(cons));
4849  /* we know that this constraint stays merged but later on we have to resort */
4850  consdata->merged = TRUE;
4851 
4852  /* second we add the constraint index to the list of indices where this variable occurs */
4853  assert(SCIPhashmapExists(vartoindex, (void*) addvar));
4854 
4855  /* correct local data structure, add constraint entry to variable data */
4856  SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4857 
4858  /* we need the new pointer to the variables, because due to adding variables it is possible that we
4859  * did reallocate the variables array inside the constraint, the index v should stay the same because the
4860  * added variable was inserted at the end and we are decreasing v in our for loop
4861  */
4862  vars = consdata->vars;
4863  nvars = consdata->nvars;
4864 
4865  /* we need to update our data structure */
4866 
4867  /* resize clique array if necessary, due to adding variables */
4868  if( (*maxnvars) < nvars )
4869  {
4870  while( (*maxnvars) < nvars )
4871  (*maxnvars) *= 2 ;
4872  SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) );
4873  }
4874  (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE;
4875 
4876  ++(*nadded);
4877  (*chgcons) = TRUE;
4878  }
4879  }
4880  }
4881 
4882  return SCIP_OKAY;
4883 }
4884 
4885 /** perform all collected aggregations */
4886 static
4888  SCIP*const scip, /**< SCIP data structure */
4889  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4890  SCIP_VAR**const undoneaggrvars, /**< aggregation variables storage */
4891  SCIP_Bool*const undoneaggrtypes, /**< aggregation type storage, type FALSE means the aggregation is of the
4892  * form x + y = 1; type TRUE means the aggregation is of the form x = y;
4893  */
4894  int const naggregations, /**< number of aggregations to performed */
4895  int*const naggrvars, /**< pointer to count number of aggregated variables */
4896  SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
4897  )
4898 { /*lint --e{715}*/
4899  SCIP_VAR* var1;
4900  SCIP_VAR* var2;
4901  SCIP_Bool aggregated;
4902  SCIP_Bool redundant;
4903  int a;
4904 
4905  assert(scip != NULL);
4906  assert(conshdlrdata != NULL);
4907  assert(undoneaggrvars != NULL);
4908  assert(undoneaggrtypes != NULL);
4909  assert(naggregations > 0);
4910  assert(naggrvars != NULL);
4911  assert(cutoff != NULL);
4912 
4913  /* loop over all open aggregations and try to aggregate them */
4914  for( a = 0; a < naggregations; ++a )
4915  {
4916  var1 = undoneaggrvars[2 * a];
4917  var2 = undoneaggrvars[2 * a + 1];
4918  assert(var1 != NULL);
4919  assert(var2 != NULL);
4920 
4921  SCIPdebugMsg(scip, "trying to aggregate <%s> %s <%s>%s\n", SCIPvarGetName(var1), undoneaggrtypes[a] ? "=" : "+", SCIPvarGetName(var2), undoneaggrtypes[a] ? "" : " = 1");
4922 
4923 #ifdef VARUSES
4924  /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate,
4925  * and increase usage counting again
4926  */
4927  SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var1) );
4928  SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var2) );
4929 #endif
4930 
4931  /* aggregate last remaining variables in the set partitioning constraint */
4932  if( undoneaggrtypes[a] )
4933  {
4934  SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, -1.0, 0.0, cutoff, &redundant, &aggregated) );
4935  }
4936  else
4937  {
4938  SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) );
4939  }
4940 
4941  if( *cutoff )
4942  {
4943  SCIPdebugMsg(scip, "aggregation was infeasible\n");
4944 
4945  return SCIP_OKAY;
4946  }
4947  /* binary variables should always be aggregated, or due to fixation the aggregation is redundant */
4948  assert(redundant);
4949 
4950  if( aggregated )
4951  ++(*naggrvars);
4952 
4953 #ifdef VARUSES
4954  /* increase variable usage counting again */
4955  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var1) );
4956  SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var2) );
4957 #endif
4958  }
4959 
4960  return SCIP_OKAY;
4961 }
4962 
4963 /** check whether we can combine or grow cliques so some constraints become redundant or we can fix variables */
4964 /** @todo try another variant, by building up the clique graph and delete unnecessary (transitive closure) edges and do
4965  * a bfs search to search for common ancestors to get all possible lifting variables
4966  */
4967 static
4969  SCIP*const scip, /**< SCIP data structure */
4970  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4971  SCIP_CONS**const conss, /**< constraint set */
4972  int const nconss, /**< number of constraints in constraint set */
4973  int const nrounds, /**< actual presolving round */
4974  int*const firstchange, /**< pointer to store first changed constraint */
4975  int*const firstclique, /**< pointer to store first constraint to start adding clique again */
4976  int*const lastclique, /**< pointer to store last constraint to add cliques again */
4977  int*const nfixedvars, /**< pointer to count number of deleted variables */
4978  int*const naggrvars, /**< pointer to count number of aggregated variables */
4979  int*const ndelconss, /**< pointer to count number of deleted constraints */
4980  int*const nchgcoefs, /**< pointer to count number of deleted coefficients */
4981  SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
4982  )
4983 {
4984  /* extend cliques/constraints by checking whether some variables are in the same clique, no pairwise clique lifting
4985  * which would be slower
4986  */
4987  SCIP_CONS** usefulconss; /* array with pointers of constraint of setpartitioning and setpacking type */
4988  SCIP_VAR** usefulvars; /* array with pointers of variables in setpartitioning and setpacking constraints */
4989  int** varconsidxs; /* array consisting of constraint indices in which the corresponding variable exists */
4990  int* varnconss; /* array consisting of number of constraints the variable occurs */
4991  int* maxnvarconsidx; /* maximal number of occurrences of a variable */
4992  int* countofoverlapping = NULL; /* the amount of variables which are in another constraint */
4993  SCIP_Bool* cliquevalues = NULL; /* values of clique-variables, either one if the variable is active or zero if the variable is negated */
4994 
4995  SCIP_HASHMAP* vartoindex; /* mapping of SCIP variables to indices */
4996  SCIP_CONSDATA* consdata;
4997 
4998  SCIP_Bool chgcons0;
4999  int nvars;
5000  int c;
5001  int v;
5002  int nusefulconss;
5003  int nusefulvars;
5004  int susefulvars;
5005  int maxnvars;
5006  int varindex;
5007 
5008  SCIP_VAR** undoneaggrvars; /* storage for not yet performed aggregations */
5009  SCIP_Bool* undoneaggrtypes; /* storage for not yet performed aggregation type (x = y or x + y = 1) */
5010  int saggregations;
5011  int naggregations;
5012 
5013  assert(scip != NULL);
5014  assert(conshdlrdata != NULL);
5015  assert(conss != NULL || nconss == 0);
5016  assert(firstchange != NULL);
5017  assert(firstclique != NULL);
5018  assert(lastclique != NULL);
5019  assert(nfixedvars != NULL);
5020  assert(naggrvars != NULL);
5021  assert(ndelconss != NULL);
5022  assert(nchgcoefs != NULL);
5023  assert(cutoff != NULL);
5024 
5025  *cutoff = FALSE;
5026 
5027  if( nconss == 0 )
5028  return SCIP_OKAY;
5029 
5030  nvars = SCIPgetNVars(scip);
5031 
5032  if( nvars == 0 )
5033  return SCIP_OKAY;
5034 
5035  susefulvars = 2 * nvars; /* two times because of negated vars, maybe due to deleted variables we need to increase this */
5036 
5037  /* a hashmap from varindex to postion in varconsidxs array, because above is still too small */
5038  SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nvars) );
5039 
5040  /* get temporary memory for the aggregation storage, to memorize aggregations which will be performed later, otherwise we would destroy our local data structures */
5041  saggregations = nvars;
5042  SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrvars, 2 * saggregations) );
5043  SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrtypes, saggregations) );
5044  BMSclearMemoryArray(undoneaggrtypes, saggregations);
5045  naggregations = 0;
5046 
5047  /* get temporary memory for all clique constraints, all appearing variables and the mapping from variables to constraints */
5048  SCIP_CALL( SCIPallocBufferArray(scip, &usefulconss, nconss) );
5049  SCIP_CALL( SCIPallocBufferArray(scip, &usefulvars, susefulvars) );
5050  BMSclearMemoryArray(usefulvars, susefulvars);
5051  SCIP_CALL( SCIPallocBufferArray(scip, &varnconss, susefulvars + 1) );
5052  BMSclearMemoryArray(varnconss, susefulvars + 1);
5053  SCIP_CALL( SCIPallocBufferArray(scip, &maxnvarconsidx, susefulvars + 1) );
5054  SCIP_CALL( SCIPallocBufferArray(scip, &varconsidxs, susefulvars + 1) );
5055  BMSclearMemoryArray(varconsidxs, susefulvars + 1);
5056  nusefulvars = 0;
5057  nusefulconss = 0;
5058  maxnvars = 0;
5059 
5060  /* @todo: check for round limit for adding extra clique constraints */
5061  /* adding clique constraints which arises from global clique information */
5062  if( conshdlrdata->nclqpresolve == 0 && conshdlrdata->addvariablesascliques )
5063  {
5064  SCIP_VAR** vars = SCIPgetVars(scip);
5065  SCIP_VAR** binvars;
5066  int* cliquepartition;
5067  int ncliques;
5068  int nbinvars;
5069  int naddconss;
5070 
5071  nbinvars = SCIPgetNBinVars(scip);
5072  SCIP_CALL( SCIPduplicateBufferArray(scip, &binvars, vars, nbinvars) );
5073  SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nbinvars) );
5074 
5075  /* @todo: check for better permutations/don't permute the first round
5076  * @todo: take binary variables which are not of vartype SCIP_VARTYPE_BINARY into account
5077  */
5078  SCIPrandomPermuteArray(conshdlrdata->randnumgen, (void**)binvars, 0, nbinvars);
5079 
5080  /* try to create a clique-partition over all binary variables and create these cliques as new setppc constraints
5081  * and add them to the usefulconss array and adjust all necessary data this will hopefully lead to faster
5082  * detection of redundant constraints
5083  */
5084  SCIP_CALL( SCIPcalcCliquePartition(scip, binvars, nbinvars, cliquepartition, &ncliques) );
5085 
5086  /* resize usefulconss array if necessary */
5087  SCIP_CALL( SCIPreallocBufferArray(scip, &usefulconss, nconss + ncliques) );
5088 
5089  naddconss = 0;
5090 
5091  /* add extra clique constraints resulting from the cliquepartition calculation to SCIP and to the local data structure */
5092  SCIP_CALL( addExtraCliques(scip, binvars, nbinvars, cliquepartition, ncliques, usefulconss, &nusefulconss,
5093  nrounds, nfixedvars, &naddconss, ndelconss, nchgcoefs, cutoff) );
5094 
5095  /* bad hack, we don't want to count these artificial created constraints if they got deleted, so ndelconss
5096  * can become negative which will be change to zero at the end of this method if it's still negative
5097  */
5098  *ndelconss -= naddconss;
5099 
5100  SCIPfreeBufferArray(scip, &cliquepartition);
5101  SCIPfreeBufferArray(scip, &binvars);
5102 
5103  if( *cutoff )
5104  goto TERMINATE;
5105  }
5106 
5107  /* start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these
5108  * constraints
5109  */
5110  SCIP_CALL( collectCliqueConss(scip, conss, nconss, usefulconss, &nusefulconss, nfixedvars, ndelconss, nchgcoefs, cutoff) );
5111  /* @Note: Even after the call above some constraints can have fixed variables, because it might happen that caused by
5112  * mergeMultiplies some variables were fixed which occurred already in previous constraints
5113  */
5114  if( *cutoff )
5115  goto TERMINATE;
5116 
5117  /* no usefulconss found */
5118  if( nusefulconss <= 1 )
5119  goto TERMINATE;
5120 
5121  /* @todo: maybe sort them after biggest indices too, or another variant would be to restore the order as they were
5122  * read in
5123  */
5124  /* sort constraints first after type (partitioning before packing) and second after number of variables such that the
5125  * partitioning constraints have increasing number of variables and the packing constraints have decreasing number of
5126  * variables, because we loop from back to front we sort them downwards, so they are the other way around
5127  */
5128  SCIPsortDownPtr((void**)usefulconss, setppcConssSort, nusefulconss);
5129 
5130  /* creating all necessary data in array structure, collect all clique constraint variables and occurrences */
5131  SCIP_CALL( collectCliqueData(scip, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs, &maxnvars) );
5132  assert(maxnvars > 0);
5133 
5134  /* allocate temporary memory for actual clique */
5135  SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, maxnvars) );
5136  /* allocate temporary memory for counting an overlap of variables */
5137  SCIP_CALL( SCIPallocBufferArray(scip, &countofoverlapping, nusefulconss) );
5138 
5139  /* sort usefulvars after indices of variables, negated and active counterparts will stand side by side */
5140  SCIPsortDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, nusefulvars);
5141 
5142  /* extend cliques/constraints by checking whether some variables of a second constraint are in the same clique */
5143  for( c = nusefulconss - 1; c >= 0 && !SCIPisStopped(scip); --c )
5144  {
5145  SCIP_VAR** cons0vars; /* these are the clique variables */
5146  SCIP_CONS* cons0;
5147  int ncons0vars;
5148  SCIP_VAR* var0;
5149  int v1;
5150  int nadded; /* number of possible added variables to constraint */
5151  int cons0fixedzeros;
5152  int oldnchgcoefs;
5153 #ifndef NDEBUG
5154  const int oldnaggrvars = *naggrvars;
5155 #endif
5156  cons0 = usefulconss[c];
5157 
5158  if( !SCIPconsIsActive(cons0) )
5159  continue;
5160 
5161  /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
5162  * possible
5163  */
5164  SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
5165 
5166  if( *cutoff )
5167  break;
5168 
5169  /* we can't handle aggregated variables later on so we should have saved them for later */
5170  assert(*naggrvars == oldnaggrvars);
5171 
5172  if( !SCIPconsIsActive(cons0) )
5173  continue;
5174 
5175  /* we need to determine the cliquedata in each iteration because we eventual will change it later */
5176  consdata = SCIPconsGetData(cons0);
5177  assert(consdata != NULL);
5178 
5179  cons0vars = consdata->vars;
5180  ncons0vars = consdata->nvars;
5181 
5182  /* sorting array after indices of variables, negated and active counterparts will stand side by side */
5183  SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5184  /* standard setppc-sorting now lost */
5185  consdata->sorted = FALSE;
5186 
5187  /* clique array should be long enough */
5188  assert(maxnvars >= ncons0vars);
5189 
5190  /* clear old entries in overlapping constraint */
5191  BMSclearMemoryArray(countofoverlapping, nusefulconss);
5192 
5193  /* calculate overlapping */
5194  for( v = ncons0vars - 1; v >= 0 ; --v )
5195  {
5196  var0 = cons0vars[v];
5197 
5198  /* fixed variables later to the count */
5199  if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 )
5200  continue;
5201 
5202  assert(SCIPhashmapExists(vartoindex, (void*) var0));
5203 
5204  varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0);
5205  for( v1 = varnconss[varindex] - 1; v1 >= 0 ; --v1 )
5206  ++(countofoverlapping[varconsidxs[varindex][v1]]);
5207  }
5208 
5209  oldnchgcoefs = *nchgcoefs;
5210  cons0fixedzeros = consdata->nfixedzeros;
5211 
5212  chgcons0 = FALSE;
5213 
5214  /* check for overlapping constraint before starting lifting */
5215  SCIP_CALL( checkForOverlapping(scip, cons0, c, c, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex,
5216  varnconss, maxnvarconsidx, varconsidxs, countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0,
5217  undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations,
5218  nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) );
5219 
5220  if( *cutoff )
5221  break;
5222 
5223  /* we can't handle aggregated variables later on so we should have saved them for later */
5224  assert(*naggrvars == oldnaggrvars);
5225 
5226  /* if cons0 changed, we need to reorder the variables */
5227  if( chgcons0 && *nchgcoefs > oldnchgcoefs )
5228  {
5229  consdata = SCIPconsGetData(cons0);
5230  assert(consdata != NULL);
5231 
5232  cons0vars = consdata->vars;
5233  ncons0vars = consdata->nvars;
5234 
5235  /* sorting array after indices of variables, negated and active counterparts will stand side by side */
5236  SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5237  /* standard setppc-sorting now lost */
5238  consdata->sorted = FALSE;
5239  }
5240 
5241  /* check cons0 again for redundancy/fixings, because due to fixings in all other constraints it might happen that cons0 is redundant now */
5242  if( consdata->nfixedones > 0 || consdata->nfixedzeros > cons0fixedzeros )
5243  {
5244  /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
5245  * possible
5246  */
5247  SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
5248 
5249  if( *cutoff )
5250  break;
5251 
5252  /* we can't handle aggregated variables later on so we should have saved them for later */
5253  assert(*naggrvars == oldnaggrvars);
5254 
5255  if( !SCIPconsIsActive(cons0) )
5256  continue;
5257  }
5258 
5259  nadded = 0;
5260 
5261  /* iterate over the cliques variables and all possible new clique variables at the "same" time, determine starting
5262  * index
5263  *
5264  * @note: it might be better to start the first round with our computed v1, but maybe it's better to switch to
5265  * trying to add all variables the second time for set packing constraints
5266  */
5267 
5268  /* we try to add all variables to the partitioning constraints, to try to fix as much as possible */
5269  if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
5270  v1 = nusefulvars - 1;
5271  else
5272  {
5273  /* if we already ran a presolving round we want to try to add new variables */
5274  if( conshdlrdata->nclqpresolve > 0 )
5275  v1 = nusefulvars - 1;
5276  else
5277  {
5278  /* find start position of variable which we will try to add to our constraint, so we will get better clique constraints */
5279  (void) SCIPsortedvecFindDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, (void*)cons0vars[ncons0vars - 1], nusefulvars, &v1);
5280  assert(v1 >= 0 && v1 < nusefulvars);
5281  /* if constraint is not merged and we found a variable which is negated the same as it's neighbour we have to
5282  * increase v1 to make sure that we don't loose this important variable */
5283  if( v1 + 1 < nusefulvars && ((SCIPvarIsNegated(usefulvars[v1 + 1]) && SCIPvarGetNegatedVar(usefulvars[v1 + 1]) == usefulvars[v1]) || (SCIPvarIsNegated(usefulvars[v1]) && SCIPvarGetNegatedVar(usefulvars[v1]) == usefulvars[v1 + 1])) )
5284  ++v1;
5285  }
5286  }
5287 
5288  assert(maxnvars >= ncons0vars);
5289  /* initialize the cliquevalues array */
5290  for( v = ncons0vars - 1; v >= 0; --v )
5291  {
5292  if( SCIPvarGetLbLocal(cons0vars[v]) < 0.5 && SCIPvarGetUbLocal(cons0vars[v]) > 0.5 )
5293  {
5294  /* variable has to be either active or a negated variable of an active one */
5295  assert(SCIPvarIsActive(cons0vars[v]) || (SCIPvarGetStatus(cons0vars[v]) == SCIP_VARSTATUS_NEGATED &&
5296  SCIPvarIsActive(SCIPvarGetNegationVar(cons0vars[v]))));
5297  cliquevalues[v] = SCIPvarIsActive(cons0vars[v]) ? TRUE : FALSE;
5298  }
5299  }
5300 
5301  chgcons0 = FALSE;
5302 
5303  /* try to lift variables to cons0 */
5304  SCIP_CALL( liftCliqueVariables(scip, cons0, c, usefulvars, &nusefulvars, v1, &cliquevalues, vartoindex, varnconss,
5305  maxnvarconsidx, varconsidxs, &maxnvars, &nadded, &chgcons0, nfixedvars, ndelconss, cutoff) );
5306 
5307  if( *cutoff )
5308  break;
5309 
5310  if( !SCIPconsIsActive(cons0) )
5311  continue;
5312 
5313  /* check for redundant constraints due to changing cons0 */
5314  if( chgcons0 )
5315  {
5316  int i;
5317 
5318  *firstchange = MIN(*firstchange, c);
5319  *firstclique = MIN(*firstclique, c);
5320  *lastclique = MAX(*lastclique, c);
5321 
5322  /* variables array has changed due to lifting variables, so get new values */
5323  assert(consdata == SCIPconsGetData(cons0));
5324  cons0vars = consdata->vars;
5325  ncons0vars = consdata->nvars;
5326 
5327  /* resorting array, because we added new variables, in order of indices of variables, negated
5328  * and active counterparts would stand side by side
5329  */
5330  SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5331  /* standard setppc-sorting now lost */
5332  consdata->sorted = FALSE;
5333 
5334  /* clear old entries in overlapping constraint */
5335  BMSclearMemoryArray(countofoverlapping, nusefulconss);
5336 
5337  for( v = ncons0vars - 1; v >= 0 ; --v )
5338  {
5339  var0 = cons0vars[v];
5340 
5341  /* fixed variables later to the count */
5342  if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 )
5343  continue;
5344 
5345  assert(SCIPhashmapExists(vartoindex, (void*) var0));
5346 
5347  varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0);
5348  for( i = varnconss[varindex] - 1; i >= 0 ; --i )
5349  ++(countofoverlapping[varconsidxs[varindex][i]]);
5350  }
5351 
5352  chgcons0 = FALSE;
5353 
5354  /* check for overlapping constraint after lifting, in the first round we will only check up front */
5355  SCIP_CALL( checkForOverlapping(scip, cons0, c, (conshdlrdata->nclqpresolve > 0) ? nusefulconss : c,
5356  usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs,
5357  countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0,
5358  undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations,
5359  nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) );
5360 
5361  if( *cutoff )
5362  break;
5363 
5364  /* we can't handle aggregated variables later on so we should have saved them for later */
5365  assert(*naggrvars == oldnaggrvars);
5366  }
5367  }
5368 
5369  TERMINATE:
5370  SCIPfreeBufferArrayNull(scip, &countofoverlapping);
5371  SCIPfreeBufferArrayNull(scip, &cliquevalues);
5372 
5373  /* free temporary memory for constraints, variables and the mapping between them in reverse order as they were
5374  * allocated
5375  */
5376  for( c = nusefulvars; c > 0; --c )
5377  {
5378  if( varconsidxs[c] != NULL )
5379  {
5380  SCIPfreeBufferArrayNull(scip, &(varconsidxs[c]));
5381  }
5382  }
5383 
5384  SCIPfreeBufferArray(scip, &varconsidxs);
5385  SCIPfreeBufferArray(scip, &maxnvarconsidx);
5386  SCIPfreeBufferArray(scip, &varnconss);
5387  SCIPfreeBufferArray(scip, &usefulvars);
5388  SCIPfreeBufferArray(scip, &usefulconss);
5389 
5390  /* perform all collected aggregations */
5391  if( !*cutoff && naggregations > 0 && !SCIPdoNotAggr(scip) )
5392  {
5393  SCIP_CALL( performAggregations(scip, conshdlrdata, undoneaggrvars, undoneaggrtypes, naggregations, naggrvars, cutoff) );
5394  }
5395 
5396  /* free temporary memory for the aggregation storage */
5397  SCIPfreeBufferArray(scip, &undoneaggrtypes);
5398  SCIPfreeBufferArray(scip, &undoneaggrvars);
5399 
5400  /* free hashmap */
5401  SCIPhashmapFree(&vartoindex);
5402 
5403  if( *ndelconss < 0 )
5404  *ndelconss = 0;
5405 
5406  return SCIP_OKAY;
5407 }
5408 
5409 
5410 /** add cliques to SCIP */
5411 static
5413  SCIP* scip, /**< SCIP data structure */
5414  SCIP_CONS** conss, /**< constraint set */
5415  int nconss, /**< number of constraints in constraint set */
5416  int firstclique, /**< first constraint to start to add cliques */
5417  int lastclique, /**< last constraint to start to add cliques */
5418  int* naddconss, /**< pointer to count number of added constraints */
5419  int* ndelconss, /**< pointer to count number of deleted constraints */
5420  int* nchgbds, /**< pointer to count number of changed bounds */
5421  SCIP_Bool* cutoff /**< pointer to store if the problem is infeasible due to a fixing */
5422  )
5423 {
5424  SCIP_CONS* cons;
5425  SCIP_CONSDATA* consdata;
5426  SCIP_Bool infeasible;
5427  int nlocalbdchgs;
5428  int c;
5429 
5430  assert(scip != NULL);
5431  assert(firstclique >= 0);
5432  assert(lastclique <= nconss);
5433  assert(conss != NULL || ((nconss == 0) && (lastclique == 0)));
5434 
5435  /* add clique and implication information */
5436  for( c = firstclique; c < lastclique; ++c )
5437  {
5438  cons = conss[c]; /*lint !e613*/
5439  assert(cons != NULL);
5440 
5441  /* ignore deleted constraints */
5442  if( !SCIPconsIsActive(cons) )
5443  continue;
5444 
5445  nlocalbdchgs = 0;
5446  SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, &nlocalbdchgs, cutoff) );
5447  *nchgbds += nlocalbdchgs;
5448 
5449  if( *cutoff )
5450  return SCIP_OKAY;
5451 
5452  consdata = SCIPconsGetData(cons);
5453  assert(consdata != NULL);
5454 
5455  if( SCIPconsIsDeleted(cons) )
5456  continue;
5457 
5458  if( !consdata->cliqueadded && consdata->nvars >= 2 )
5459  {
5460  /* add a set partitioning / packing constraint as clique */
5461  if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5462  {
5463  SCIP_CALL( SCIPaddClique(scip, consdata->vars, NULL, consdata->nvars,
5464  ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING), &infeasible, &nlocalbdchgs) );
5465  *nchgbds += nlocalbdchgs;
5466 
5467  if( infeasible )
5468  {
5469  *cutoff = TRUE;
5470  return SCIP_OKAY;
5471  }
5472  }
5473  else if( consdata->nvars == 2 && !SCIPconsIsModifiable(cons) )
5474  {
5475  /* a two-variable set covering constraint x + y >= 1 yields the implication x == 0 -> y == 1 */
5476  SCIP_CALL( SCIPaddVarImplication(scip, consdata->vars[0], FALSE, consdata->vars[1],
5477  SCIP_BOUNDTYPE_LOWER, 1.0, &infeasible, &nlocalbdchgs) );
5478  *nchgbds += nlocalbdchgs;
5479 
5480  if( infeasible )
5481  {
5482  *cutoff = TRUE;
5483  return SCIP_OKAY;
5484  }
5485  }
5486  consdata->cliqueadded = TRUE;
5487  }
5488  }
5489 
5490  return SCIP_OKAY;
5491 }
5492 
5493 /** perform multi-aggregation on variables resulting from a set-partitioning/-packing constraint */
5494 static
5496  SCIP* scip, /**< SCIP data structure */
5497  SCIP_Bool linearconshdlrexist,/**< does the linear constraint handler exist, necessary for multi-aggregations */
5498  SCIP_VAR** vars, /**< all variables including the variable to which will be multi-aggregated */
5499  int nvars, /**< number of all variables */
5500  int pos, /**< position of variable for multi-aggregation */
5501  SCIP_Bool* infeasible, /**< pointer to store infeasibility status of aggregation */
5502  SCIP_Bool* aggregated /**< pointer to store aggregation status */
5503  )
5504 {
5505  SCIP_VAR** tmpvars;
5506  SCIP_Real* scalars;
5507  int v;
5508 
5509  assert(scip != NULL);
5510  assert(vars != NULL);
5511  assert(nvars > 1);
5512  assert(0 <= pos && pos < nvars);
5513  assert(infeasible != NULL);
5514  assert(aggregated != NULL);
5515 
5516  if( nvars == 2 )
5517  {
5518  SCIP_Bool redundant;
5519 
5520  /* perform aggregation on variables resulting from a set-packing constraint */
5521  SCIP_CALL( SCIPaggregateVars(scip, vars[pos], vars[nvars - pos - 1], 1.0, 1.0, 1.0, infeasible, &redundant, aggregated) );
5522 
5523  if( *aggregated )
5524  SCIPdebugMsg(scip, "aggregated %s = 1 - %s\n", SCIPvarGetName(vars[pos]), SCIPvarGetName(vars[nvars - pos - 1]));
5525 
5526  return SCIP_OKAY;
5527  }
5528 
5529  if( !linearconshdlrexist )
5530  {
5531  *infeasible = FALSE;
5532  return SCIP_OKAY;
5533  }
5534 
5535  /* if the last variable will be multi-aggregated, we do not need to copy the variables */
5536  if( pos == nvars - 1 )
5537  tmpvars = vars;
5538  else
5539  {
5540  /* copy variables for aggregation */
5541  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
5542  tmpvars[pos] = tmpvars[nvars - 1];
5543  }
5544 
5545  SCIP_CALL( SCIPallocBufferArray(scip, &scalars, nvars - 1) );
5546  /* initialize scalars */
5547  for( v = nvars - 2; v >= 0; --v )
5548  scalars[v] = -1.0;
5549 
5550  SCIPdebugMsg(scip, "multi-aggregating binary variable <%s> (locks: [%d,%d]; to %d variables)\n",
5552  SCIPvarGetNLocksUpType(vars[pos], SCIP_LOCKTYPE_MODEL), nvars - 1);
5553 
5554  /* perform multi-aggregation */
5555  SCIP_CALL( SCIPmultiaggregateVar(scip, vars[pos], nvars - 1, tmpvars, scalars, 1.0, infeasible, aggregated) );
5556  assert(!(*infeasible));
5557 
5558  SCIPfreeBufferArray(scip, &scalars);
5559 
5560  if( pos < nvars - 1 )
5561  {
5562  assert(tmpvars != vars);
5563  SCIPfreeBufferArray(scip, &tmpvars);
5564  }
5565 
5566  return SCIP_OKAY;
5567 }
5568 
5569 /** determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and negated)
5570  * in any combination of set-partitioning and set-packing constraints
5571  *
5572  * we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint or
5573  * even delete it
5574  *
5575  * 1. c1: x + y + z = 1, uplocks(x) = 1, downlocks(x) = 1 => x = 1 - y - z and change c1 to y + z <= 1
5576  *
5577  * 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
5578  *
5579  * 3. d1: x + y + z <= 1 and d2: ~x + u + v <= 1, uplocks(x) = 1, downlocks(x) = 1
5580  * a) obj(x) <= 0 => x = 1 - y - z and delete d1
5581  * b) obj(x) > 0 => ~x = 1 - u - v and delete d2
5582  *
5583  * 4. e1: x + y + z == 1 and e2: ~x + u + v (<= or ==) 1, uplocks(x) = (1 or 2), downlocks(x) = 2
5584  * => x = 1 - y - z and delete e1
5585  *
5586  * we can also aggregate a variable in a set-packing constraint with only two variables when the uplocks are equal to
5587  * one and then delete this constraint
5588  *
5589  * 5. f1: x + y <= 1, uplocks(x) = 1, obj(x) <= 0 => x = 1 - y and delete f1
5590  *
5591  * @todo might want to multi-aggregate variables even with more locks, when the fill in is still smaller or equal to
5592  * the old number of non-zeros, e.g.
5593  *
5594  * x + y + z = 1
5595  * ~x + u + v <=/= 1
5596  * ~x + w <= 1
5597  */
5598 static
5600  SCIP* scip, /**< SCIP data structure */
5601  SCIP_CONS** conss, /**< constraint set */
5602  int nconss, /**< number of constraints in constraint set */
5603  SCIP_Bool dualpresolvingenabled,/**< is dual presolving enabled */
5604  SCIP_Bool linearconshdlrexist,/**< does the linear constraint handler exist, necessary for
5605  * multi-aggregations
5606  */
5607  int* nfixedvars, /**< pointer to count number of deleted variables */
5608  int* naggrvars, /**< pointer to count number of aggregated variables */
5609  int* ndelconss, /**< pointer to count number of deleted constraints */
5610  int* nchgcoefs, /**< pointer to count number of changed coefficients */
5611  int* nchgsides, /**< pointer to count number of changed left hand sides */
5612  SCIP_Bool* cutoff /**< pointer to store if a cut off was detected */
5613  )
5614 {
5615  SCIP_CONS** usefulconss;
5616  SCIP_VAR** binvars;
5617  SCIP_HASHMAP* vartoindex;
5618  SCIP_Bool* chgtype;
5619  int* considxs;
5620  int* posincons;
5621  SCIP_Bool infeasible;
5622  SCIP_Bool aggregated;
5623  SCIP_Bool donotaggr;
5624  SCIP_Bool donotmultaggr;
5625  SCIP_Bool mustcheck;
5626  SCIP_Bool addcut;
5627  int nposvars;
5628  int ndecs;
5629  int nbinvars;
5630  int nposbinvars;
5631  int nuplocks;
5632  int ndownlocks;
5633 #ifndef NDEBUG
5634  int posreplacements = 0;
5635 #endif
5636  int nhashmapentries;
5637  int nlocaladdconss;
5638  int v;
5639  int c;
5640 
5641  assert(scip != NULL);
5642  assert(conss != NULL);
5643  assert(nconss > 0);
5644  assert(nfixedvars != NULL);
5645  assert(naggrvars != NULL);
5646  assert(ndelconss != NULL);
5647  assert(nchgcoefs != NULL);
5648  assert(nchgsides != NULL);
5649 
5650  nbinvars = SCIPgetNBinVars(scip);
5651  nposbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5652  assert(nbinvars + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip) == nposbinvars);
5653 
5654  binvars = SCIPgetVars(scip);
5655 
5656  /* determine number for possible multi-aggregations */
5657  nposvars = 0;
5658  for( v = nposbinvars - 1; v >= 0; --v )
5659  {
5660  assert(SCIPvarGetType(binvars[v]) != SCIP_VARTYPE_CONTINUOUS);
5661 
5662  if( v < nbinvars || SCIPvarIsBinary(binvars[v]) )
5663  {
5664  nuplocks = SCIPvarGetNLocksUpType(binvars[v], SCIP_LOCKTYPE_MODEL);
5665  ndownlocks = SCIPvarGetNLocksDownType(binvars[v], SCIP_LOCKTYPE_MODEL);
5666 
5667  if( (nuplocks == 1 && ndownlocks <= 1) || (nuplocks <= 1 && ndownlocks == 1) || (nuplocks <= 2 && ndownlocks <= 2 && SCIPvarGetNegatedVar(binvars[v]) != NULL) )
5668  ++nposvars;
5669  }
5670  }
5671 
5672  SCIPdebugMsg(scip, "found %d binary variables for possible multi-aggregation\n", nposvars);
5673 
5674  if( nposvars == 0 )
5675  return SCIP_OKAY;
5676 
5677  /* a hashmap from var to index when found in a set-partitioning constraint */
5678  SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nposvars) );
5679 
5680  /* get temporary memory */
5681  SCIP_CALL( SCIPallocBufferArray(scip, &chgtype, nconss) );
5682  BMSclearMemoryArray(chgtype, nconss);
5683 
5684  SCIP_CALL( SCIPallocBufferArray(scip, &considxs, nposbinvars) );
5685  SCIP_CALL( SCIPallocBufferArray(scip, &posincons, nposbinvars) );
5686 
5687  SCIP_CALL( SCIPduplicateBufferArray(scip, &usefulconss, conss, nconss) );
5688  /* sort constraints */
5689  SCIPsortPtr((void**)usefulconss, setppcConssSort2, nconss);
5690 
5691  nhashmapentries = 0;
5692  ndecs = 0;
5693  donotaggr = SCIPdoNotAggr(scip);
5694  donotmultaggr = SCIPdoNotMultaggr(scip);
5695  assert(!donotaggr || !donotmultaggr);
5696 
5697  /* determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and
5698  * negated) in any combination of set-partitioning and set-packing constraints
5699  *
5700  * we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint
5701  * or even delete it
5702  */
5703  for( c = 0; c < nconss; ++c )
5704  {
5705  SCIP_CONS* cons;
5706  SCIP_CONSDATA* consdata;
5707  int oldnfixedvars;
5708  nlocaladdconss = 0;
5709 
5710  cons = usefulconss[c];
5711  assert(cons != NULL);
5712 
5713  if( SCIPconsIsDeleted(cons) )
5714  continue;
5715 
5716  consdata = SCIPconsGetData(cons);
5717  assert(consdata != NULL);
5718 
5719  /* if we cannot find any constraint to perform a useful multi-aggregation, stop */
5720  if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING )
5721  break;
5722 
5723  if( !SCIPconsIsChecked(cons) )
5724  continue;
5725 
5726  if( SCIPconsIsModifiable(cons) )
5727  continue;
5728 
5729  /* update the variables */
5730  SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
5731 
5732  if( *cutoff )
5733  break;
5734 
5735  /* due to resolving multi-aggregations a constraint can become deleted */
5736  if( SCIPconsIsDeleted(cons) )
5737  continue;
5738 
5739  SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) );
5740  assert(!addcut);
5741 
5742  if( *cutoff )
5743  break;
5744 
5745  if( SCIPconsIsDeleted(cons) )
5746  continue;
5747 
5748  oldnfixedvars = *nfixedvars;
5749 
5750  /* merging unmerged constraints */
5751  SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
5752 
5753  if( *cutoff )
5754  break;
5755 
5756  if( SCIPconsIsDeleted(cons) )
5757  continue;
5758 
5759  if( oldnfixedvars < *nfixedvars )
5760  {
5761  /* update the variables */
5762  SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
5763  assert(!SCIPconsIsDeleted(cons));
5764  assert(nlocaladdconss == 0);
5765  assert(!*cutoff);
5766 
5767  if( SCIPconsIsDeleted(cons) )
5768  continue;
5769  }
5770 
5771  /* if the constraint was not merged and consists of a variable with its negation, the constraint is redundant */
5772  if( consdata->nvars < 2 )
5773  {
5774  /* deleting redundant set-packing constraint */
5775  if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5776  {
5777  SCIPdebugMsg(scip, "deleting redundant set-packing constraint <%s>\n", SCIPconsGetName(cons));
5778 
5779  SCIP_CALL( SCIPdelCons(scip, cons) );
5780  ++(*ndelconss);
5781 
5782  continue;
5783  }
5784  else
5785  {
5786  SCIP_Bool fixed;
5787 
5788  assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
5789 
5790  if( consdata->nvars == 0 )
5791  {
5792  SCIPdebugMsg(scip, "empty set partition constraint <%s> led to infeasibility\n", SCIPconsGetName(cons));
5793 
5794  *cutoff = TRUE;
5795  break;
5796  }
5797 
5798  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));
5799 
5800  SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], 1.0, &infeasible, &fixed) );
5801  assert(!infeasible);
5802 
5803  if( fixed )
5804  ++(*nfixedvars);
5805 
5806  assert(SCIPvarGetLbGlobal(consdata->vars[0]) > 0.5);
5807 
5808  SCIPdebugMsg(scip, "deleting redundant set-partition constraint <%s>\n", SCIPconsGetName(cons));
5809 
5810  SCIP_CALL( SCIPdelCons(scip, cons) );
5811  ++(*ndelconss);
5812 
5813  continue;
5814  }
5815  }
5816 
5817  /* perform dualpresolve on set-packing constraints with exactly two variables */
5818