Scippy

SCIP

Solving Constraint Integer Programs

cons_linking.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-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_linking.c
17  * @brief constraint handler for linking constraints
18  * @author Stefan Heinz
19  * @author Jens Schulz
20  *
21  * The constraints handler stores linking constraints between an integer variable and an array of binary variables. Such
22  * a linking constraint has the form:
23  *
24  * intvar = sum_{i=1}^n {vals[i] * binvars[i]}
25  *
26  * with the additional side condition that exactly one binary variable has to be one (set partitioning condition).
27  *
28  * This constraint can be created only with the integer variable. In this case the binary variables are only created on
29  * demand. That is, whenever someone asks for the binary variables. Therefore, such constraints can be used to get a
30  * "binary representation" of the domain of the integer variable which will be dynamically created.
31  *
32  *
33  * @todo add pairwise comparison of constraints in presolving (fast hash table version and complete pairwise comparison)
34  * @todo in case the integer variable is set to lower or upper bound it follows that only the corresponding binary
35  * variable has a positive value which is one, this can be used to fasten the checking routine
36  */
37 
38 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
39 
40 #include <assert.h>
41 #include <string.h>
42 #include <ctype.h>
43 
44 #include "scip/cons_linear.h"
45 #include "scip/cons_linking.h"
46 #include "scip/cons_setppc.h"
47 
48 /* constraint handler properties */
49 #define CONSHDLR_NAME "linking"
50 #define CONSHDLR_DESC "linking constraint x = sum_{i=1}^{n} c_i*y_i, y1+...+yn = 1, x integer, y's binary"
51 
52 #define EVENTHDLR_NAME "linking"
53 #define EVENTHDLR_DESC "event handler for linking constraints"
54 
55 #define CONSHDLR_SEPAPRIORITY 750000 /**< priority of the constraint handler for separation */
56 #define CONSHDLR_ENFOPRIORITY -2050000 /**< priority of the constraint handler for constraint enforcing */
57 #define CONSHDLR_CHECKPRIORITY -750000 /**< priority of the constraint handler for checking feasibility */
58 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
59 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
60 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation, propagation and enforcement, -1 for no eager evaluations, 0 for first only */
61 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
62 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
63 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
64 #define CONSHDLR_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
65 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
66 
67 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
68 
69 
70 #define HASHSIZE_BINVARSCONS 131101 /**< minimal size of hash table in linking constraint handler */
71 #define DEFAULT_LINEARIZE FALSE /**< should the linking constraint be linearize after the binary variable are created */
72 
73 /*
74  * Data structures
75  */
76 
77 /** constraint data for linking constraints */
78 struct SCIP_ConsData
79 {
80  SCIP_VAR* intvar; /**< integer variable which is linked */
81  SCIP_VAR** binvars; /**< binary variables */
82  int* vals; /**< coefficients */
83  SCIP_ROW* row1; /**< LP row for the linking itself */
84  SCIP_ROW* row2; /**< LP row ensuring the set partitioning condition of the binary variables */
85  int nbinvars; /**< number of binary variables */
86  int sizebinvars; /**< size of the binary variable array */
87  int nfixedzeros; /**< current number of variables fixed to zero in the constraint */
88  int nfixedones; /**< current number of variables fixed to one in the constraint */
89  int firstnonfixed; /**< index of first locally non-fixed binary variable in binvars array */
90  int lastnonfixed; /**< index of last locally non-fixed binary variable in binvars array */
91  unsigned int cliqueadded:1; /**< was the set partitioning condition already added as clique? */
92  unsigned int sorted:1; /**< are the coefficients of the binary variables are sorted in non-decreasing order */
93 };
94 
95 /** constraint handler data */
96 struct SCIP_ConshdlrData
97 {
98  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events on binary variables */
99  SCIP_HASHMAP* varmap; /**< hash map mapping an integer variable to its linking constraint */
100  SCIP_Bool linearize; /**< should the linking constraint be linearize after the binary variable are created */
101 };
102 
103 /*
104  * Local methods
105  */
106 
107 /** returns for a given integer variable the corresponding hash map key */
108 static
110  SCIP_VAR* var /**< variable to get the hash map key for */
111  )
112 {
113  /* return the unique variable index + 1 */
114  return (void*)(size_t)(SCIPvarGetIndex(var) + 1);
115 }
116 
117 /* sort binary variable in non-decreasing order w.r.t. coefficients */
118 static
120  SCIP_CONSDATA* consdata /**< linking constraint data */
121  )
122 {
123  if( consdata->sorted )
124  return;
125 
126  /* sort binary variable in non-decreasing order w.r.t. coefficients */
127  SCIPsortIntPtr(consdata->vals, (void**)consdata->binvars, consdata->nbinvars);
128 
129  consdata->sorted = TRUE;
130 }
131 
132 
133 /** installs rounding locks for the binary variables in the given linking constraint */
134 static
136  SCIP* scip, /**< SCIP data structure */
137  SCIP_CONS* cons, /**< linking constraint */
138  SCIP_VAR** binvars, /**< binary variables */
139  int nbinvars /**< number of binary variables */
140  )
141 {
142  int b;
143 
144  for( b = 0; b < nbinvars; ++b )
145  {
146  SCIP_CALL( SCIPlockVarCons(scip, binvars[b], cons, TRUE, TRUE) );
147  }
148 
149  return SCIP_OKAY;
150 }
151 
152 /** creates constraint handler data for the linking constraint handler */
153 static
155  SCIP* scip, /**< SCIP data structure */
156  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
157  SCIP_EVENTHDLR* eventhdlr /**< event handler */
158  )
159 {
160  assert(scip != NULL);
161  assert(conshdlrdata != NULL);
162  assert(eventhdlr != NULL);
163 
164  SCIP_CALL( SCIPallocMemory(scip, conshdlrdata) );
165 
166  /* create hash map */
167  (*conshdlrdata)->varmap = NULL;
168 
169  /* set event handler for bound change events on binary variables */
170  (*conshdlrdata)->eventhdlr = eventhdlr;
171 
172  return SCIP_OKAY;
173 }
174 
175 /** frees constraint handler data for linking constraint handler */
176 static
178  SCIP* scip, /**< SCIP data structure */
179  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
180  )
181 {
182  assert(conshdlrdata != NULL);
183  assert(*conshdlrdata != NULL);
184 
185  /* free hash map */
186  if( (*conshdlrdata)->varmap != NULL )
187  SCIPhashmapFree(&(*conshdlrdata)->varmap);
188 
189  /* free memory of constraint handler data */
190  SCIPfreeMemory(scip, conshdlrdata);
191 
192  return SCIP_OKAY;
193 }
194 
195 /** prints linking constraint to file stream */
196 static
198  SCIP* scip, /**< SCIP data structure */
199  SCIP_CONSDATA* consdata, /**< linking constraint data */
200  FILE* file /**< output file (or NULL for standard output) */
201  )
202 {
203  SCIP_VAR** binvars;
204  SCIP_VAR* intvar;
205  int nbinvars;
206  int b;
207 
208  assert(scip != NULL);
209  assert(consdata != NULL);
210 
211  intvar = consdata->intvar;
212  binvars = consdata->binvars;
213  nbinvars = consdata->nbinvars;
214 
215  assert(intvar != NULL);
216  assert(binvars != NULL || nbinvars == 0);
217 
218  /* print integer variable */
219  SCIP_CALL( SCIPwriteVarName(scip, file, intvar, FALSE) );
220 
221  SCIPinfoMessage(scip, file, " = ");
222 
223  if( nbinvars == 0 )
224  {
225  SCIPinfoMessage(scip, file, " no binary variables yet");
226  }
227  else
228  {
229  SCIP_Real* vals;
230 
231  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nbinvars) );
232 
233  assert(binvars != NULL);
234 
235  /* convert integer coefficients into SCIP_Real */
236  for( b = 0; b < nbinvars; ++b )
237  {
238  vals[b] = (SCIP_Real)consdata->vals[b];
239  }
240 
241  SCIP_CALL( SCIPwriteVarsLinearsum(scip, file, binvars, vals, nbinvars, FALSE) );
242 
243  SCIPfreeBufferArray(scip, &vals);
244  }
245 
246  return SCIP_OKAY;
247 }
248 
249 /** catches events for variable at given position */
250 static
252  SCIP* scip, /**< SCIP data structure */
253  SCIP_CONSDATA* consdata, /**< linking constraint data */
254  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
255  int pos /**< array position of variable to catch bound change events for */
256  )
257 {
258  SCIP_VAR* var;
259 
260  assert(consdata != NULL);
261  assert(eventhdlr != NULL);
262  assert(0 <= pos && pos < consdata->nbinvars);
263  assert(consdata->binvars != NULL);
264 
265  var = consdata->binvars[pos];
266  assert(var != NULL);
267 
268  /* catch bound change events on variable */
269  /**@todo do we have to add the event SCIP_EVENTTYPE_VARFIXED? */
270  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
271 
272  /* update the fixed variables counters for this variable */
273  if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
274  consdata->nfixedzeros++;
275  else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
276  consdata->nfixedones++;
277 
278  return SCIP_OKAY;
279 }
280 
281 /** drops events for variable at given position */
282 static
284  SCIP* scip, /**< SCIP data structure */
285  SCIP_CONSDATA* consdata, /**< linking constraint data */
286  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
287  int pos /**< array position of variable to catch bound change events for */
288  )
289 {
290  SCIP_VAR* var;
291 
292  assert(consdata != NULL);
293  assert(eventhdlr != NULL);
294  assert(0 <= pos && pos < consdata->nbinvars);
295  assert(consdata->binvars != NULL);
296 
297  var = consdata->binvars[pos];
298  assert(var != NULL);
299 
300  /* drop events on variable */
301  SCIP_CALL( SCIPdropVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
302 
303  /* update the fixed variables counters for this variable */
304  if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
305  consdata->nfixedzeros--;
306  else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
307  consdata->nfixedones--;
308 
309  return SCIP_OKAY;
310 }
311 
312 /** catches bound change events for all variables in transformed linking constraint */
313 static
315  SCIP* scip, /**< SCIP data structure */
316  SCIP_CONSDATA* consdata, /**< linking constraint data */
317  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
318  )
319 {
320  int i;
321 
322  assert(consdata != NULL);
323 
324  if( consdata->nbinvars <= 1 )
325  return SCIP_OKAY;
326 
327  /* catch event for every single variable */
328  for( i = 0; i < consdata->nbinvars; ++i )
329  {
330  SCIP_CALL( catchEvent(scip, consdata, eventhdlr, i) );
331  }
332 
333  return SCIP_OKAY;
334 }
335 
336 /** drops bound change events for all variables in transformed linking constraint */
337 static
339  SCIP* scip, /**< SCIP data structure */
340  SCIP_CONSDATA* consdata, /**< linking constraint data */
341  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
342  )
343 {
344  int i;
345 
346  assert(consdata != NULL);
347 
348  if( consdata->nbinvars <= 1 )
349  return SCIP_OKAY;
350 
351  /* drop event of every single variable */
352  for( i = 0; i < consdata->nbinvars; ++i )
353  {
354  SCIP_CALL( dropEvent(scip, consdata, eventhdlr, i) );
355  }
356 
357  return SCIP_OKAY;
358 }
359 
360 /** linearize the given linking constraint into a set partitioning constraint for the binary variables and a linear
361  * constraint for the linking between the integer variable and the binary variables */
362 static
364  SCIP* scip, /**< SCIP data structure */
365  SCIP_CONS* cons, /**< linking constraint */
366  SCIP_CONSDATA* consdata /**< linking constraint data */
367  )
368 {
369  SCIP_CONS* lincons;
370  int b;
371 
372  SCIPdebugMessage("linearized linking constraint <%s>\n", SCIPconsGetName(cons));
373 
374  /* create set partitioning constraint for the binary variables */
375  SCIP_CALL( SCIPcreateConsSetpart(scip, &lincons, SCIPconsGetName(cons), consdata->nbinvars, consdata->binvars,
379  SCIP_CALL( SCIPaddCons(scip, lincons) );
380  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
381 
382  /* create linear constraint for the linking between the binary variables and the integer variable */
383  SCIP_CALL( SCIPcreateConsLinear(scip, &lincons, SCIPconsGetName(cons), 0, NULL, NULL, 0.0, 0.0,
387 
388  for( b = 0; b < consdata->nbinvars; ++b )
389  {
390  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, consdata->binvars[b], (SCIP_Real)consdata->vals[b]) );
391  }
392  SCIP_CALL( SCIPaddCoefLinear(scip, lincons, consdata->intvar, -1.0) );
393 
394  SCIP_CALL( SCIPaddCons(scip, lincons) );
395  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
396 
397  return SCIP_OKAY;
398 }
399 
400 /** creates the binary variables */
401 static
403  SCIP* scip, /**< SCIP data structure */
404  SCIP_CONS* cons, /**< linking constraint */
405  SCIP_CONSDATA* consdata, /**< linking constraint data */
406  SCIP_EVENTHDLR* eventhdlr, /**< event handler for bound change events on binary variables */
407  SCIP_Bool linearize /**< should the linking constraint be linearized */
408  )
409 {
410  SCIP_VAR* intvar;
411  SCIP_VAR* binvar;
412  char name[SCIP_MAXSTRLEN];
413  int nbinvars;
414  int lb;
415  int ub;
416  int b;
417 
418  assert(scip != NULL);
419  assert(consdata != NULL);
420  assert(consdata->nbinvars == 0);
421  assert(consdata->binvars == NULL);
422 
423  SCIPdebugMessage("create binary variables for integer variable <%s>\n", SCIPvarGetName(consdata->intvar));
424 
425  intvar = consdata->intvar;
426  lb = (int)(SCIPvarGetLbGlobal(intvar) + 0.5);
427  ub = (int)(SCIPvarGetUbGlobal(intvar) + 0.5);
428  nbinvars = ub-lb+1;
429  assert(nbinvars > 0);
430 
431  /* allocate block memory for the binary variables */
432  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->binvars, nbinvars) );
433  consdata->sizebinvars = nbinvars;
434 
435  /* check if the integer variable is fixed */
436  if( nbinvars == 1 )
437  {
438  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s[%d]", SCIPvarGetName(intvar), lb);
439 
440  /* creates and captures a fixed binary variables */
441  SCIP_CALL( SCIPcreateVar(scip, &binvar, name, 1.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
442  FALSE, TRUE, NULL, NULL, NULL, NULL, NULL) );
443  SCIP_CALL( SCIPaddVar(scip, binvar) );
444 
445  consdata->binvars[0] = binvar;
446  consdata->vals[0] = lb;
447  }
448  else
449  {
450  for( b = 0; b < nbinvars; ++b)
451  {
452  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s[%d]", SCIPvarGetName(intvar), lb + b);
453 
454  /* creates and captures variables */
455  SCIP_CALL( SCIPcreateVar(scip, &binvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
456  TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
457 
458  /* add variable to the problem */
459  SCIP_CALL( SCIPaddVar(scip, binvar) );
460  consdata->binvars[b] = binvar;
461  consdata->vals[b] = lb + b;
462  }
463  }
464 
465  consdata->nbinvars = nbinvars;
466 
467  assert(consdata->nfixedzeros == 0);
468  assert(consdata->nfixedones == 0);
469 
470  if( SCIPisTransformed(scip) )
471  {
472  /* (rounding) lock binary variable */
473  SCIP_CALL( lockRounding(scip, cons, consdata->binvars, consdata->nbinvars) );
474 
475  /* catch bound change events of variables */
476  SCIP_CALL( catchAllEvents(scip, consdata, eventhdlr) );
477 
478  if( nbinvars > 1 )
479  {
480  if( linearize )
481  {
482  SCIP_CALL( consdataLinearize(scip, cons, consdata) );
483  }
484  else
485  {
486  /* enable constraint */
487  SCIP_CALL( SCIPenableCons(scip, cons) );
488  }
489  }
490  }
491 
492  return SCIP_OKAY;
493 }
494 
495 /** creates consdata */
496 static
498  SCIP* scip, /**< SCIP data structure */
499  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
500  SCIP_CONSDATA** consdata, /**< pointer to constraint data */
501  SCIP_VAR* intvar, /**< integer variable which is linked */
502  SCIP_VAR** binvars, /**< binary variables */
503  int* vals, /**< coefficients of the binary variables */
504  int nbinvars /**< number of binary starting variables */
505  )
506 {
507  int v;
508 
509  assert(scip!= NULL);
510  assert(consdata != NULL);
511  assert(intvar != NULL);
512  assert(binvars != NULL || nbinvars == 0);
513  assert(SCIPvarGetType(intvar) != SCIP_VARTYPE_CONTINUOUS);
514 
515  /* allocate memory for consdata */
516  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
517 
518  (*consdata)->intvar = intvar;
519  (*consdata)->nbinvars = nbinvars;
520  (*consdata)->sizebinvars = nbinvars;
521  (*consdata)->row1 = NULL;
522  (*consdata)->row2 = NULL;
523  (*consdata)->cliqueadded = FALSE;
524 
525  /* initialize constraint state */
526  (*consdata)->sorted = FALSE;
527  (*consdata)->firstnonfixed = 0;
528  (*consdata)->lastnonfixed = nbinvars - 1;
529  (*consdata)->nfixedzeros = 0;
530  (*consdata)->nfixedones = 0;
531 
532  if( nbinvars == 0 )
533  {
534  (*consdata)->binvars = NULL;
535  (*consdata)->vals = NULL;
536  }
537  else
538  {
539  /* copy binary variable array */
540  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->binvars, binvars, nbinvars) );
541 
542  /* copy coefficients */
543  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vals, vals, nbinvars) );
544  }
545 
546  /* get transformed variable, if we are in the transformed problem */
547  if( SCIPisTransformed(scip) )
548  {
549  if( nbinvars > 0 )
550  {
551  SCIP_CALL( SCIPgetTransformedVars(scip, nbinvars, (*consdata)->binvars, (*consdata)->binvars) );
552 
553  /* catch bound change events of variables */
554  SCIP_CALL( catchAllEvents(scip, *consdata, eventhdlr) );
555  }
556 
557  SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->intvar, &(*consdata)->intvar) );
558  }
559 
560  /* mark integer variable to be not multi-aggregated */
561  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->intvar) );
562 
563  /* capture variables */
564  for( v = 0; v < nbinvars; ++v )
565  {
566  assert((*consdata)->binvars[v] != NULL);
567  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->binvars[v]) );
568  }
569  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->intvar) );
570 
571  return SCIP_OKAY;
572 }
573 
574 
575 /** free consdata */
576 static
578  SCIP* scip, /**< SCIP data structure */
579  SCIP_CONSDATA** consdata /**< pointer to consdata */
580  )
581 {
582  int v;
583 
584  assert(consdata != NULL);
585  assert(*consdata != NULL);
586  assert((*consdata)->nbinvars == 0 || (*consdata)->binvars != NULL);
587 
588  /* release the rows */
589  if( (*consdata)->row1 != NULL )
590  {
591  assert((*consdata)->row2 != NULL);
592 
593  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row1) );
594  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row2) );
595  }
596 
597  /* capture variables */
598  for( v = 0; v < (*consdata)->nbinvars; ++v )
599  {
600  assert((*consdata)->binvars[v] != NULL);
601  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->binvars[v]) );
602  }
603  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->intvar) );
604 
605  /* free binary variable array */
606  if( (*consdata)->sizebinvars > 0 )
607  {
608  /* if constraint belongs to transformed problem space, drop bound change events on variables */
609  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vals, (*consdata)->sizebinvars);
610  SCIPfreeBlockMemoryArray(scip, &(*consdata)->binvars, (*consdata)->sizebinvars);
611  }
612 
613  /* check if the fixed counters are reset */
614  assert((*consdata)->nfixedzeros == 0);
615  assert((*consdata)->nfixedones == 0);
616 
617  /* free constraint data */
618  SCIPfreeBlockMemory(scip, consdata);
619 
620  return SCIP_OKAY;
621 }
622 
623 
624 /** analyzes conflicting assignment on given constraint where reason comes from the integer variable lower or upper
625  * bound
626  */
627 static
629  SCIP* scip, /**< SCIP data structure */
630  SCIP_CONS* cons, /**< linking constraint to be processed */
631  SCIP_VAR* intvar, /**< integer variable */
632  SCIP_VAR* binvar, /**< binary variable is the reason */
633  SCIP_Bool lbintvar, /**< lower bound of integer variable is the reason */
634  SCIP_Bool ubintvar /**< upper bound of integer variable is the reason */
635  )
636 {
637  assert(scip != NULL);
638 
639  /* conflict analysis can only be applied in solving stage and if it is turned on */
641  return SCIP_OKAY;
642 
643  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
645 
646  if( lbintvar )
647  {
648  assert(intvar != NULL);
649  SCIP_CALL( SCIPaddConflictLb(scip, intvar, NULL) );
650  }
651 
652  if( ubintvar )
653  {
654  assert(intvar != NULL);
655  SCIP_CALL( SCIPaddConflictUb(scip, intvar, NULL) );
656  }
657 
658  if( binvar != NULL )
659  {
660  SCIP_CALL( SCIPaddConflictBinvar(scip, binvar) );
661  }
662 
663  /* analyze the conflict */
664  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
665 
666  return SCIP_OKAY;
667 }
668 
669 /** fix integer variable to the value of the binary variable at pos */
670 static
672  SCIP* scip, /**< SCIP data structure */
673  SCIP_CONS* cons, /**< linking constraint to be processed */
674  int pos, /**< position of binary variable */
675  SCIP_Bool* cutoff /**< pointer to store TRUE, if the node can be cut off */
676  )
677 {
678  SCIP_CONSDATA* consdata;
679  SCIP_VAR* intvar;
680  SCIP_Bool infeasible;
681  SCIP_Bool tightened;
682  SCIP_Real coef;
683 
684  consdata = SCIPconsGetData(cons);
685  assert(consdata != NULL);
686 
687  intvar = consdata->intvar;
688  coef = (SCIP_Real)consdata->vals[pos];
689 
690  /* change lower bound of the integer variable */
691  SCIP_CALL( SCIPinferVarLbCons(scip, intvar, coef, cons, pos, TRUE, &infeasible, &tightened) );
692 
693  if( infeasible )
694  {
695  assert(coef > SCIPvarGetUbLocal(intvar));
696  assert(coef >= SCIPvarGetLbLocal(intvar));
697 
698  SCIP_CALL( analyzeConflict(scip, cons, intvar, consdata->binvars[pos], FALSE, TRUE) );
699 
700  *cutoff = TRUE;
701  return SCIP_OKAY;
702  }
703  assert(coef <= SCIPvarGetUbLocal(intvar));
704 
705  /* change upper bound of the integer variable */
706  SCIP_CALL( SCIPinferVarUbCons(scip, intvar, coef, cons, pos, TRUE, &infeasible, &tightened) );
707 
708  if( infeasible )
709  {
710  assert(coef < SCIPvarGetLbLocal(intvar));
711  assert(coef <= SCIPvarGetUbLocal(intvar));
712 
713  SCIP_CALL( analyzeConflict(scip, cons, intvar, consdata->binvars[pos], TRUE, FALSE) );
714 
715  *cutoff = TRUE;
716  return SCIP_OKAY;
717  }
718 
719  assert((int)(SCIPvarGetUbLocal(intvar)+0.5) == (int)(SCIPvarGetLbLocal(intvar)+0.5) );
720 
721  return SCIP_OKAY;
722 }
723 
724 /** checks constraint for violation from the local bound of the integer variable, applies fixings to the binary
725  * variables if possible
726  */
727 static
729  SCIP* scip, /**< SCIP data structure */
730  SCIP_CONS* cons, /**< linking constraint to be processed */
731  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
732  int* nchgbds, /**< pointer to store the number of changes (foxed) variable bounds */
733  SCIP_Bool* mustcheck /**< pointer to store whether this constraint must be checked for feasibility */
734  )
735 {
736  SCIP_CONSDATA* consdata;
737  SCIP_VAR** binvars;
738  SCIP_VAR* intvar;
739  int* vals;
740  int nbinvars;
741  int lblocal;
742  int ublocal;
743  int b;
744  SCIP_Bool infeasible;
745  SCIP_Bool tightened;
746 
747  assert(cons != NULL);
748  assert(SCIPconsGetHdlr(cons) != NULL);
749  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
750  assert(cutoff != NULL);
751  assert(nchgbds != NULL);
752  assert(mustcheck != NULL);
753 
754  consdata = SCIPconsGetData(cons);
755  assert(consdata != NULL);
756 
757  /* ensure that the binary variables are sorted in non-decreasing order w.r.t. their coefficients */
758  consdataSort(consdata);
759 
760  nbinvars = consdata->nbinvars;
761 
762  /* in case there is only at most one binary variables, the constraints should already be disabled */
763  assert(nbinvars > 1);
764 
765  /* if more than one binary variable is fixed to one or at least nbinvars minus one variable are fixed to zero */
766  if( consdata->nfixedones > 0 || consdata->nfixedzeros >= nbinvars-1 )
767  return SCIP_OKAY;
768 
769  intvar = consdata->intvar;
770  assert(intvar != NULL);
771 
772  binvars = consdata->binvars;
773  vals = consdata->vals;
774 
775  lblocal = (int)(SCIPvarGetLbLocal(intvar) + 0.5);
776  ublocal = (int)(SCIPvarGetUbLocal(intvar) + 0.5);
777  assert(lblocal <= ublocal);
778 
779 #ifndef NDEBUG
780  /* check that the first variable are locally fixed to zero */
781  for( b = 0; b < consdata->firstnonfixed; ++b )
782  assert(SCIPvarGetUbLocal(binvars[b]) < 0.5);
783 
784  /* check that the last variable are locally fixed to zero */
785  for( b = consdata->lastnonfixed + 1; b < nbinvars; ++b )
786  assert(SCIPvarGetUbLocal(binvars[b]) < 0.5);
787 #endif
788 
789  for( b = consdata->firstnonfixed; b < nbinvars; ++b )
790  {
791  if( vals[b] < lblocal )
792  {
793  SCIP_VAR* var;
794 
795  var = binvars[b];
796  assert(var != NULL);
797 
798  SCIPdebugMessage("fix variable <%s> to zero due to the lower bound of the integer variable <%s> [%g,%g]\n",
799  SCIPvarGetName(var), SCIPvarGetName(intvar), SCIPvarGetLbLocal(intvar), SCIPvarGetUbLocal(intvar));
800 
801  SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, -2, &infeasible, &tightened) );
802 
803  if( infeasible )
804  {
805  SCIP_CALL( analyzeConflict(scip, cons, intvar, var, TRUE, FALSE) );
806  *cutoff = TRUE;
807  return SCIP_OKAY;
808  }
809 
810  if( tightened )
811  (*nchgbds)++;
812 
813  /* adjust constraint state */
814  consdata->firstnonfixed++;
815  }
816  else
817  break;
818  }
819  assert(consdata->firstnonfixed <= consdata->lastnonfixed);
820 
821  /* fix binary variables to zero if not yet fixed, from local upper bound + 1*/
822  for( b = consdata->lastnonfixed; b >= 0; --b )
823  {
824  if( vals[b] > ublocal )
825  {
826  SCIP_VAR* var;
827 
828  var = binvars[b];
829  assert(var != NULL);
830 
831  SCIPdebugMessage("fix variable <%s> to zero due to the upper bound of the integer variable <%s> [%g,%g]\n",
832  SCIPvarGetName(var), SCIPvarGetName(intvar), SCIPvarGetLbLocal(intvar), SCIPvarGetUbLocal(intvar));
833 
834  SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, -3, &infeasible, &tightened) );
835 
836  if( infeasible )
837  {
838  SCIP_CALL( analyzeConflict(scip, cons, intvar, var, FALSE, TRUE) );
839  *cutoff = TRUE;
840  return SCIP_OKAY;
841  }
842 
843  if( tightened )
844  (*nchgbds)++;
845 
846  /* adjust constraint state */
847  consdata->lastnonfixed--;
848  }
849  else
850  break;
851  }
852 
853  if( consdata->firstnonfixed > consdata->lastnonfixed )
854  {
855  *cutoff = TRUE;
856  return SCIP_OKAY;
857  }
858 
859  *mustcheck = (*nchgbds) == 0;
860 
861  /* if integer variables is fixed, create for the binary variables which have a coefficient equal to the fixed vale a
862  * set partitioning constraint
863  */
864  if( lblocal == ublocal )
865  {
866  if( consdata->firstnonfixed == consdata->lastnonfixed )
867  {
868  SCIP_VAR* var;
869 
870  var = binvars[consdata->firstnonfixed];
871 
872  SCIPdebugMessage("fix variable <%s> to one due to the fixed integer variable <%s> [%g,%g]\n",
873  SCIPvarGetName(var), SCIPvarGetName(intvar), SCIPvarGetLbLocal(intvar), SCIPvarGetUbLocal(intvar));
874 
875  SCIP_CALL( SCIPinferBinvarCons(scip, var, TRUE, cons, -6, &infeasible, &tightened) );
876 
877  if( infeasible )
878  {
879  SCIP_CALL( analyzeConflict(scip, cons, intvar, var, TRUE, TRUE) );
880  *cutoff = TRUE;
881  return SCIP_OKAY;
882  }
883 
884  if( tightened )
885  (*nchgbds)++;
886 
887  SCIPdebugMessage(" -> disabling linking constraint <%s>\n", SCIPconsGetName(cons));
888  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
889 
890  *mustcheck = FALSE;
891  }
892  else if( SCIPgetDepth(scip) <= 0 )
893  {
894  SCIP_CONS* setppc;
895  SCIP_VAR** vars;
896  int nvars;
897 
898  /* get sub array of variables which have the same coefficient */
899  vars = &consdata->binvars[consdata->firstnonfixed];
900  nvars = consdata->lastnonfixed - consdata->firstnonfixed + 1;
901 
902  SCIP_CALL( SCIPcreateConsSetpart(scip, &setppc, SCIPconsGetName(cons), nvars, vars,
906 
907  SCIP_CALL( SCIPaddCons(scip, setppc) );
908  SCIP_CALL( SCIPreleaseCons(scip, &setppc) );
909 
910  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
911  }
912  }
913 
914  return SCIP_OKAY;
915 }
916 
917 /** deletes coefficient at given position from the binary variable array */
918 static
920  SCIP* scip, /**< SCIP data structure */
921  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
922  SCIP_CONS* cons, /**< linking constraint */
923  int pos /**< position of coefficient to delete */
924  )
925 {
926  SCIP_CONSDATA* consdata;
927  SCIP_VAR* var;
928 
929  assert(scip != NULL);
930  assert(eventhdlr != NULL);
931 
932  consdata = SCIPconsGetData(cons);
933  assert(consdata != NULL);
934  assert(0 <= pos && pos < consdata->nbinvars);
935 
936  var = consdata->binvars[pos];
937  assert(var != NULL);
938  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
939 
940  /* remove the rounding locks for the deleted variable */
941  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
942 
943  /* if we are in transformed problem, delete the event data of the variable */
944  if( SCIPconsIsTransformed(cons) )
945  {
946  SCIP_CONSHDLR* conshdlr;
947  SCIP_CONSHDLRDATA* conshdlrdata;
948 
949  /* get event handler */
950  conshdlr = SCIPconsGetHdlr(cons);
951  conshdlrdata = SCIPconshdlrGetData(conshdlr);
952  assert(conshdlrdata != NULL);
953  assert(conshdlrdata->eventhdlr != NULL);
954 
955  /* drop bound change events of variable */
956  SCIP_CALL( dropEvent(scip, consdata, conshdlrdata->eventhdlr, pos) );
957  }
958 
959  /* move the last variable to the free slot */
960  if( pos != consdata->nbinvars - 1 )
961  {
962  consdata->binvars[pos] = consdata->binvars[consdata->nbinvars-1];
963  consdata->vals[pos] = consdata->vals[consdata->nbinvars-1];
964  consdata->sorted = FALSE;
965  }
966 
967  consdata->nbinvars--;
968 
969  /* release variable */
970  SCIP_CALL( SCIPreleaseVar(scip, &var) );
971 
972  return SCIP_OKAY;
973 }
974 
975 /** remove the trailing and leeading binary variable which are fixed to zero */
976 static
978  SCIP* scip, /**< SCIP data structure */
979  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
980  SCIP_CONS* cons /**< linking constraint */
981  )
982 {
983  SCIP_CONSDATA* consdata;
984  int nbinvars;
985  int b;
986 
987  consdata = SCIPconsGetData(cons);
988  assert(consdata != NULL);
989  assert(consdata->sorted);
990 
991  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING || SCIPgetDepth(scip) <= 0);
992  assert(!SCIPinProbing(scip));
993  assert(!SCIPinRepropagation(scip));
994 
995  nbinvars = consdata->nbinvars;
996 
997  for( b = nbinvars - 1; b > consdata->lastnonfixed; --b )
998  {
999  SCIP_CALL( delCoefPos(scip, eventhdlr, cons, b) );
1000  }
1001 
1002  for( b = consdata->firstnonfixed - 1; b >= 0; --b )
1003  {
1004  SCIP_CALL( delCoefPos(scip, eventhdlr, cons, b) );
1005  }
1006 
1007  for( b = consdata->nbinvars - 1; b >= 0; --b )
1008  {
1009  if( SCIPvarGetUbLocal(consdata->binvars[b]) < 0.5 )
1010  {
1011  SCIP_CALL( delCoefPos(scip, eventhdlr, cons, b) );
1012  }
1013  }
1014 
1015  /* set the constraint state */
1016  consdata->firstnonfixed = 0;
1017  consdata->lastnonfixed = consdata->nbinvars - 1;
1018 
1019  return SCIP_OKAY;
1020 }
1021 
1022 /** tightened the integer variable due to binary variables which are fixed to zero */
1023 static
1025  SCIP* scip, /**< SCIP data structure */
1026  SCIP_CONS* cons, /**< linking constraint to be processed */
1027  SCIP_CONSDATA* consdata, /**< linking constraint to be processed */
1028  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1029  int* nchgbds /**< pointer to store the number of changed variable bounds */
1030  )
1031 {
1032  SCIP_VAR** binvars;
1033  SCIP_VAR* intvar;
1034  int* vals;
1035 
1036  SCIP_Bool infeasible;
1037  SCIP_Bool tightened;
1038  int nbinvars;
1039  int b;
1040 
1041  /* if more than one binary variable is fixed to one or at least nbinvars minus one variable are fixed to zero return */
1042  if( consdata->nfixedones > 1 || consdata->nfixedzeros >= consdata->nbinvars-1 )
1043  return SCIP_OKAY;
1044 
1045  if( *cutoff )
1046  return SCIP_OKAY;
1047 
1048  assert(consdata->sorted);
1049 
1050  intvar = consdata->intvar;
1051  binvars = consdata->binvars;
1052  vals = consdata->vals;
1053  nbinvars = consdata->nbinvars;
1054 
1055 #ifndef NDEBUG
1056  /* check that the first variable are locally fixed to zero */
1057  for( b = 0; b < consdata->firstnonfixed; ++b )
1058  assert(SCIPvarGetUbLocal(binvars[b]) < 0.5);
1059 #endif
1060 
1061  assert(consdata->firstnonfixed < nbinvars);
1062  assert(consdata->lastnonfixed < nbinvars);
1063 
1064  /* find first non fixed binary variable */
1065  for( b = consdata->firstnonfixed; b < nbinvars; ++b )
1066  {
1067  if( SCIPvarGetUbLocal(binvars[b]) > 0.5 )
1068  break;
1069 
1070  consdata->firstnonfixed++;
1071  }
1072 
1073  SCIP_CALL( SCIPinferVarLbCons(scip, intvar, (SCIP_Real)vals[b], cons, -4, TRUE, &infeasible, &tightened) );
1074 
1075  /* start conflict analysis if infeasible */
1076  if( infeasible )
1077  {
1078  /* analyze the cutoff if if SOLVING stage and conflict analysis is turned on */
1080  {
1081  SCIPdebugMessage("conflict at <%s> due to bounds and fixed binvars: [lb,ub] = [%g,%g]; b= %d; coef = %d \n",
1082  SCIPvarGetName(intvar), SCIPvarGetLbLocal(intvar), SCIPvarGetUbLocal(intvar), b, vals[b]);
1083 
1085 
1086  /* ??????????? use resolve method and only add binvars which are needed to exceed the upper bound */
1087 
1088  /* add conflicting variables */
1089  SCIP_CALL( SCIPaddConflictUb(scip, intvar, NULL) );
1090 
1091  for( b = 0; b < consdata->firstnonfixed; ++b )
1092  {
1093  SCIP_CALL( SCIPaddConflictBinvar(scip, binvars[b]) );
1094  }
1095 
1096  /* analyze the conflict */
1097  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1098  }
1099 
1100  *cutoff = TRUE;
1101  return SCIP_OKAY;
1102  }
1103 
1104  if( tightened )
1105  (*nchgbds)++;
1106 
1107 #ifndef NDEBUG
1108  /* check that the last variable are locally fixed to zero */
1109  for( b = consdata->lastnonfixed + 1; b < nbinvars; ++b )
1110  assert(SCIPvarGetUbLocal(binvars[b]) < 0.5);
1111 #endif
1112 
1113  /* find last non fixed variable */
1114  for( b = consdata->lastnonfixed; b >= 0; --b )
1115  {
1116  if( SCIPvarGetUbLocal(binvars[b]) > 0.5 )
1117  break;
1118 
1119  consdata->lastnonfixed--;
1120  }
1121 
1122  SCIP_CALL( SCIPinferVarUbCons(scip, intvar, (SCIP_Real)vals[b], cons, -5, TRUE, &infeasible, &tightened) );
1123 
1124  if( infeasible )
1125  {
1126  /* conflict analysis can only be applied in solving stage and if conflict analysis is turned on */
1128  {
1129  SCIPdebugMessage("conflict at <%s> due to bounds and fixed binvars: [lb,ub] = [%g,%g]; b = %d; coef = %d,\n",
1130  SCIPvarGetName(intvar), SCIPvarGetLbLocal(intvar), SCIPvarGetUbLocal(intvar), b, vals[b]);
1131 
1133 
1134  /* ??????????? use resolve method and only add binvars which are needed to fall below the lower bound */
1135 
1136  /* add conflicting variables */
1137  SCIP_CALL( SCIPaddConflictLb(scip, intvar, NULL) );
1138 
1139  for( b = consdata->lastnonfixed + 1; b < nbinvars; ++b )
1140  {
1141  SCIP_CALL( SCIPaddConflictBinvar(scip, binvars[b]) );
1142  }
1143 
1144  /* analyze the conflict */
1145  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1146  }
1147 
1148  *cutoff = TRUE;
1149  return SCIP_OKAY;
1150  }
1151 
1152  if( tightened )
1153  (*nchgbds)++;
1154 
1155  return SCIP_OKAY;
1156 }
1157 
1158 /** checks constraint for violation only looking at the fixed binary variables, applies further fixings if possible */
1159 static
1161  SCIP* scip, /**< SCIP data structure */
1162  SCIP_CONS* cons, /**< linking constraint to be processed */
1163  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1164  int* nchgbds, /**< pointer to store the number of changed variable bounds */
1165  SCIP_Bool* addcut, /**< pointer to store whether this constraint must be added as a cut */
1166  SCIP_Bool* mustcheck /**< pointer to store whether this constraint must be checked for feasibility */
1167  )
1168 {
1169  SCIP_CONSDATA* consdata;
1170  SCIP_Bool infeasible;
1171  SCIP_Bool tightened;
1172 
1173  assert(cons != NULL);
1174  assert(SCIPconsGetHdlr(cons) != NULL);
1175  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
1176  assert(cutoff != NULL);
1177  assert(nchgbds != NULL);
1178  assert(addcut != NULL);
1179  assert(mustcheck != NULL);
1180 
1181  consdata = SCIPconsGetData(cons);
1182  assert(consdata != NULL);
1183  assert(consdata->nbinvars == 0 || consdata->binvars != NULL);
1184  assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nbinvars);
1185  assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nbinvars);
1186 
1187  /* ensure that the binary variables are sorted in non-decreasing order w.r.t. their coefficients */
1188  consdataSort(consdata);
1189 
1190  /* in case there is only at most one binary variables, the constraints should already be disabled */
1191  assert(consdata->nbinvars > 1);
1192 
1193  if( *cutoff )
1194  return SCIP_OKAY;
1195 
1196  if( consdata->nfixedones == 1 )
1197  {
1198  /* exactly one variable is fixed to 1:
1199  * - all other binary variables in a set partitioning must be zero
1200  * - integer variable are fixed to that binary variable
1201  */
1202  if( consdata->nfixedzeros < consdata->nbinvars - 1 ||
1203  SCIPisLT(scip, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar)) )
1204  {
1205  SCIP_VAR** vars;
1206  SCIP_VAR* var;
1207 #ifndef NDEBUG
1208  SCIP_Bool fixedonefound;
1209 #endif
1210  int nvars;
1211  int v;
1212 
1213  SCIPdebugMessage(" -> fixing all other variables to zero due to the set partitioning condition <%s>\n",
1214  SCIPconsGetName(cons));
1215 
1216  /* unfixed variables exist: fix them to zero;
1217  * this could result in additional variables fixed to one due to aggregations; in this case, the
1218  * constraint is infeasible in local bounds
1219  */
1220  vars = consdata->binvars;
1221  nvars = consdata->nbinvars;
1222 #ifndef NDEBUG
1223  fixedonefound = FALSE;
1224 #endif
1225 
1226  for( v = 0; v < nvars && consdata->nfixedones == 1 && !(*cutoff); ++v )
1227  {
1228  var = vars[v];
1229  assert(SCIPvarIsBinary(var));
1230  if( SCIPvarGetLbLocal(var) < 0.5 )
1231  {
1232  SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, -1, &infeasible, &tightened) );
1233  assert(!infeasible);
1234  SCIPdebugMessage(" -> fixed <%s> to zero (tightened=%u)\n", SCIPvarGetName(var), tightened);
1235  }
1236  else
1237  {
1238 #ifndef NDEBUG
1239  fixedonefound = TRUE;
1240 #endif
1241  /* fix integer variable */
1242  SCIP_CALL( consFixInteger(scip, cons, v, cutoff) );
1243  }
1244  }
1245  if( !(*cutoff) )
1246  {
1247  /* the fixed to one variable must have been found, and at least one variable must have been fixed */
1248  assert(consdata->nfixedones >= 1 || fixedonefound);
1249 
1250  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1251  (*nchgbds)++;
1252  }
1253  }
1254 
1255  /* now all other variables are fixed to zero:
1256  * the constraint is feasible, and if it's not modifiable, it is redundant
1257  */
1258  if( !SCIPconsIsModifiable(cons) && consdata->nfixedones == 1 )
1259  {
1260  SCIPdebugMessage(" -> disabling set linking constraint <%s>\n", SCIPconsGetName(cons));
1261  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
1262  }
1263  }
1264  else if( consdata->nfixedones >= 2 )
1265  {
1266  /* at least two variables are fixed to 1:
1267  * - the set partitioning condition is violated
1268  */
1269  SCIPdebugMessage(" -> conflict on "CONSHDLR_NAME" constraint <%s> due to the set partitioning condition\n", SCIPconsGetName(cons));
1270 
1271  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1272 
1273  /* conflict analysis can only be applied in solving stage and if it is applicable */
1275  {
1276  SCIP_VAR** vars;
1277  int nvars;
1278  int n;
1279  int v;
1280 
1281  vars = consdata->binvars;
1282  nvars = consdata->nbinvars;
1283 
1284  /* initialize conflict analysis, and add the two variables assigned to one to conflict candidate queue */
1286  n = 0;
1287 
1288  for( v = 0; v < nvars && n < 2; ++v )
1289  {
1290  if( SCIPvarGetLbLocal(vars[v]) > 0.5 )
1291  {
1292  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[v]) );
1293  n++;
1294  }
1295  }
1296  assert(n == 2);
1297 
1298  /* analyze the conflict */
1299  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1300  }
1301 
1302  *cutoff = TRUE;
1303  }
1304  else if( consdata->nfixedzeros == consdata->nbinvars )
1305  {
1306  /* all variables are fixed to zero:
1307  * - the set partitioning condition is violated, and if it's unmodifiable, the node
1308  * can be cut off -- otherwise, the constraint must be added as a cut and further pricing must
1309  * be performed
1310  */
1311  assert(consdata->nfixedones == 0);
1312 
1313  SCIPdebugMessage(" -> "CONSHDLR_NAME" constraint <%s> is infeasible due to the set partitioning condition\n",
1314  SCIPconsGetName(cons));
1315 
1316  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1317  if( SCIPconsIsModifiable(cons) )
1318  *addcut = TRUE;
1319  else
1320  {
1321  /* conflict analysis can only be applied in solving stage and if it is applicable */
1323  {
1324  SCIP_VAR** vars;
1325  int nvars;
1326  int v;
1327 
1328  vars = consdata->binvars;
1329  nvars = consdata->nbinvars;
1330 
1331  /* initialize conflict analysis, add all variables of infeasible constraint to conflict candidate queue */
1333  for( v = 0; v < nvars; ++v )
1334  {
1335  assert(SCIPvarGetUbLocal(vars[v]) < 0.5);
1336  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[v]) );
1337  }
1338 
1339  /* analyze the conflict */
1340  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1341  }
1342  *cutoff = TRUE;
1343  }
1344  }
1345  else if( consdata->nfixedzeros == consdata->nbinvars - 1 )
1346  {
1347  /* all variables except one are fixed to zero:
1348  * - an unmodifiable set partitioning constraint is feasible and can be disabled after the
1349  * remaining variable is fixed to one
1350  * - a modifiable set partitioning constraint must be checked manually
1351  */
1352  assert(consdata->nfixedones == 0);
1353 
1354  if( !SCIPconsIsModifiable(cons) )
1355  {
1356  SCIP_VAR** vars;
1357  SCIP_VAR* var;
1358  int nvars;
1359  int v;
1360 
1361  /* search the single variable that can be fixed */
1362  vars = consdata->binvars;
1363  nvars = consdata->nbinvars;
1364  for( v = 0; v < nvars && !(*cutoff); ++v )
1365  {
1366  var = vars[v];
1367  assert(SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)));
1368  assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0));
1369  if( SCIPvarGetUbLocal(var) > 0.5 )
1370  {
1371  assert(SCIPvarGetLbLocal(var) < 0.5);
1372  SCIPdebugMessage(" -> fixing remaining binary variable <%s> to one in "CONSHDLR_NAME" constraint <%s>\n",
1373  SCIPvarGetName(var), SCIPconsGetName(cons));
1374 
1375  SCIP_CALL( SCIPinferBinvarCons(scip, var, TRUE, cons, -1, &infeasible, &tightened) );
1376  assert(!infeasible);
1377  assert(tightened);
1378 
1379  /* fix integer variable */
1380  SCIP_CALL( consFixInteger(scip, cons, v, cutoff) );
1381  break;
1382  }
1383  }
1384  assert(v < nvars);
1385  assert(consdata->nfixedzeros == consdata->nbinvars - 1);
1386  assert(consdata->nfixedones == 1);
1387 
1388  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
1389  (*nchgbds)++;
1390  }
1391  }
1392  else
1393  {
1394  SCIP_CALL( tightenedIntvar(scip, cons, consdata, cutoff, nchgbds) );
1395  }
1396 
1397  *mustcheck = (*nchgbds) == 0;
1398 
1399  assert(consdata->nfixedzeros + consdata->nfixedones <= consdata->nbinvars);
1400 
1401  return SCIP_OKAY;
1402 }
1403 
1404 /** returns whether the given solution is feasible for the given linking constraint */
1405 static
1407  SCIP* scip, /**< SCIP data structure */
1408  SCIP_CONS* cons, /**< linking constraint to be checked */
1409  SCIP_SOL* sol /**< primal solution, or NULL for current LP/pseudo solution */
1410  )
1411 {
1412  SCIP_CONSDATA* consdata;
1413  SCIP_VAR** binvars;
1414  int* vals;
1415  SCIP_Real solval;
1416  SCIP_Real linksum;
1417  SCIP_Real setpartsum;
1418  SCIP_Real setpartsumbound;
1419  int nbinvars;
1420  int b;
1421 
1422  assert(scip != NULL);
1423  assert(cons != NULL);
1424 
1425  SCIPdebugMessage("checking linking constraint <%s> for feasibility of solution %p\n", SCIPconsGetName(cons), (void*)sol);
1426 
1427  consdata = SCIPconsGetData(cons);
1428  assert(consdata != NULL);
1429  assert(consdata->binvars != NULL || consdata->nbinvars == 0);
1430 
1431  /* in case there is only at most one binary variables, the constraints should already be disabled */
1432  assert(consdata->nbinvars > 1);
1433 
1434  /* calculate the constraint's activity for the linking part and the set partitioning part */
1435  binvars = consdata->binvars;
1436  vals = consdata->vals;
1437  nbinvars = consdata->nbinvars;
1438 
1439  linksum = 0.0;
1440  setpartsum = 0.0;
1441  setpartsumbound = 1.0 + 2*SCIPfeastol(scip);
1442 
1443  for( b = 0; b < nbinvars && setpartsum < setpartsumbound; ++b ) /* if sum >= sumbound, the feasibility is clearly decided */
1444  {
1445  assert(SCIPvarIsBinary(binvars[b]));
1446 
1447  solval = SCIPgetSolVal(scip, sol, binvars[b]);
1448  assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0));
1449 
1450  linksum += vals[b] * solval;
1451  setpartsum += solval;
1452  }
1453 
1454  /* check if the fixed binary variable match with the integer variable */
1455  return SCIPisFeasEQ(scip, linksum, SCIPgetSolVal(scip, sol, consdata->intvar)) && SCIPisFeasEQ(scip, setpartsum, 1.0);
1456 }
1457 
1458 #if 0
1459 /** transfer aggregated integer variables to the corresponding binary variables */
1460 static
1462  SCIP* scip, /**< SCIP data structure */
1463  SCIP_HASHMAP* varmap, /**< hash map mapping a integer variables to its linking constraint */
1464  SCIP_CONS** conss, /**< array of linking constraint */
1465  int nconss, /**< number of linking constraints */
1466  int* naggrvars, /**< pointer to store the number of aggregate variables */
1467  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
1468  )
1469 {
1470  SCIP_CONS* aggrcons;
1471  SCIP_CONSDATA* aggrconsdata;
1472  SCIP_CONSDATA* consdata;
1473  SCIP_VAR** binvars;
1474  SCIP_VAR** aggrbinvars;
1475  SCIP_VAR* intvar;
1476  SCIP_VAR* aggrvar;
1477  SCIP_Real aggrconst;
1478  SCIP_Real aggrscalar;
1479  SCIP_Bool infeasible;
1480  SCIP_Bool redundant;
1481  SCIP_Bool aggregated;
1482  int offset;
1483  int aggroffset;
1484  int nbinvars;
1485  int shift;
1486  int b;
1487  int c;
1488 
1489  assert(varmap != NULL);
1490 
1491  for( c = 0; c < nconss; ++c )
1492  {
1493  consdata = SCIPconsGetData(conss[c]);
1494  assert(consdata != NULL);
1495 
1496  intvar = consdata->intvar;
1497  assert(intvar != NULL);
1498 
1500  {
1501  aggrvar = SCIPvarGetAggrVar(intvar);
1502  aggrcons = (SCIP_CONS*) SCIPhashmapGetImage(varmap, getHashmapKey(aggrvar));
1503 
1504  /* check if the aggregate variable belongs to a linking constraint */
1505  if( aggrcons != NULL )
1506  {
1507  aggrconsdata = SCIPconsGetData(aggrcons);
1508  assert(aggrconsdata != NULL);
1509 
1510  aggrconst = SCIPvarGetAggrConstant(intvar);
1511  aggrscalar = SCIPvarGetAggrScalar(intvar);
1512 
1513  /**@todo extend the aggregation for those cases were the aggrscalar is not equal to 1.0 */
1514  if( SCIPisEQ(scip, aggrscalar, 1.0 ) )
1515  {
1516  /* since both variables are integer variable and the aggrscalar is 1.0 the aggrconst should
1517  * integral
1518  */
1519  assert(SCIPisIntegral(scip, aggrconst));
1520  shift = (int)(aggrconst + 0.5);
1521 
1522  offset = consdata->offset;
1523  binvars = consdata->binvars;
1524  aggroffset = aggrconsdata->offset;
1525  aggrbinvars = aggrconsdata->binvars;
1526 
1527  nbinvars = MIN(consdata->nbinvars + offset, aggrconsdata->nbinvars + shift + aggroffset);
1528 
1529  for( b = MAX(offset, aggroffset-shift); b < nbinvars; ++b )
1530  {
1531  assert(b - offset >= 0);
1532  assert(b + shift - aggroffset >= 0);
1533  assert(b < consdata->nbinvars);
1534  assert(b < aggrconsdata->nbinvars - shift);
1535 
1536  /* add aggregation x - y = 0.0 */
1537  SCIP_CALL( SCIPaggregateVars(scip, binvars[b-offset], aggrbinvars[b+shift-aggroffset], 1.0, -1.0, 0.0,
1538  &infeasible, &redundant, &aggregated) );
1539 
1540  if( infeasible )
1541  {
1542  (*cutoff) = TRUE;
1543  return SCIP_OKAY;
1544  }
1545 
1546  if( aggregated )
1547  (*naggrvars)++;
1548  }
1549  }
1550  }
1551  }
1552  }
1553  return SCIP_OKAY;
1554 }
1555 #endif
1556 
1557 /** create two rows for the linking constraint
1558  *
1559  * - row1: {sum_{b=1}^n-1 vals[b] * binvars[b]} - intvar = 0
1560  * - row2: {sum_{b=0}^n-1 binvars[b]} = 1.0
1561  */
1562 static
1564  SCIP* scip, /**< SCIP data structure */
1565  SCIP_CONS* cons /**< linking constraint */
1566  )
1567 {
1568  SCIP_CONSDATA* consdata;
1569  char rowname[SCIP_MAXSTRLEN];
1570  int b;
1571 
1572  assert( cons != NULL);
1573 
1574  /* get constraint data */
1575  consdata = SCIPconsGetData(cons);
1576  assert(consdata != NULL);
1577  assert(consdata->row1 == NULL);
1578  assert(consdata->row2 == NULL);
1579  assert(consdata->nbinvars > 1);
1580 
1581  /* create the LP row which captures the linking between the integer and binary variables */
1582  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s[link]", SCIPconsGetName(cons));
1583 
1584  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row1, SCIPconsGetHdlr(cons), rowname, 0.0, 0.0,
1586 
1587  /* add integer variable to the row */
1588  assert(consdata->intvar != NULL);
1589  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row1, consdata->intvar, -1.0) );
1590 
1591  /* adding all except the first binary variable to the row */
1592  assert(consdata->binvars != NULL);
1593  for( b = 0; b < consdata->nbinvars; ++b )
1594  {
1595  SCIP_CALL( SCIPaddVarToRow(scip, consdata->row1, consdata->binvars[b], (SCIP_Real)consdata->vals[b]) );
1596  }
1597 
1598  /* create the LP row which captures the set partitioning condition of the binary variables */
1599  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s[setppc]", SCIPconsGetName(cons));
1600  assert( consdata->nbinvars > 0 );
1601 
1602  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row2, SCIPconsGetHdlr(cons), rowname, 1.0, 1.0,
1604 
1605  SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->row2, consdata->nbinvars, consdata->binvars, 1.0) );
1606 
1607  return SCIP_OKAY;
1608 }
1609 
1610 
1611 /** adds linking constraint as cut to the LP */
1612 static
1614  SCIP* scip, /**< SCIP data structure */
1615  SCIP_CONS* cons, /**< linking constraint */
1616  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
1617  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
1618  )
1619 {
1620  SCIP_CONSDATA* consdata;
1621 
1622  assert( cutoff != NULL );
1623  *cutoff = FALSE;
1624 
1625  consdata = SCIPconsGetData(cons);
1626  assert(consdata != NULL);
1627 
1628  /* in case there is only at most one binary variables, the constraints should already be disabled */
1629  assert(consdata->nbinvars > 1);
1630 
1631  if( consdata->row1 == NULL )
1632  {
1633  assert(consdata->row2 == NULL);
1634 
1635  /* convert linking data into LP rows */
1636  SCIP_CALL( createRows(scip, cons) );
1637  }
1638  assert(consdata->row1 != NULL);
1639  assert(consdata->row2 != NULL);
1640 
1641  /* insert LP linking row as cut */
1642  if( !SCIProwIsInLP(consdata->row1) )
1643  {
1644  SCIPdebugMessage("adding linking row of constraint <%s> as cut to the LP\n", SCIPconsGetName(cons));
1645  SCIP_CALL( SCIPaddCut(scip, sol, consdata->row1, TRUE/*FALSE*/, cutoff) );
1646  }
1647 
1648  /* insert LP set partitioning row as cut */
1649  if( !SCIProwIsInLP(consdata->row2) )
1650  {
1651  SCIPdebugMessage("adding set partitioning row of constraint <%s> as cut to the LP\n", SCIPconsGetName(cons));
1652  SCIP_CALL( SCIPaddCut(scip, sol, consdata->row2, TRUE/*FALSE*/, cutoff) );
1653  }
1654 
1655  return SCIP_OKAY;
1656 }
1657 
1658 
1659 /** checks constraint for violation, and adds it as a cuts if possible */
1660 static
1662  SCIP* scip, /**< SCIP data structure */
1663  SCIP_CONS* cons, /**< linking constraint to be separated */
1664  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
1665  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1666  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
1667  int* nchgbds /**< pointer to store the number of changed variables bounds */
1668  )
1669 {
1670  SCIP_CONSDATA* consdata;
1671  SCIP_Bool addcut;
1672  SCIP_Bool mustcheck;
1673 
1674  assert(cons != NULL);
1675  assert(SCIPconsGetHdlr(cons) != NULL);
1676  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
1677  assert(cutoff != NULL);
1678  assert(separated != NULL);
1679  assert(nchgbds != NULL);
1680 
1681  consdata = SCIPconsGetData(cons);
1682  assert(consdata != NULL);
1683 
1684  /* in case there is only at most one binary variables, the constraints should already be disabled */
1685  assert(consdata->nbinvars > 1);
1686 
1687  SCIPdebugMessage("separating constraint <%s>\n", SCIPconsGetName(cons));
1688 
1689  *cutoff = FALSE;
1690  addcut = FALSE;
1691  mustcheck = TRUE;
1692 
1693  /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
1694  if( sol == NULL )
1695  {
1696  SCIP_CALL( processIntegerBoundChg(scip, cons, cutoff, nchgbds, &mustcheck) );
1697  }
1698 
1699  if( mustcheck && !(*cutoff) )
1700  {
1701  /* variable's fixings didn't give us any information -> we have to check the constraint */
1702  if( sol == NULL && consdata->row1 != NULL )
1703  {
1704  SCIP_Real feasibility;
1705  SCIP_Real tmp;
1706 
1707  assert(consdata->row2 != NULL);
1708 
1709  /* skip constraints already in the LP */
1710  if( SCIProwIsInLP(consdata->row1) && SCIProwIsInLP(consdata->row2))
1711  return SCIP_OKAY;
1712 
1713  feasibility = 1.0;
1714 
1715  /* check first row (linking) for feasibility */
1716  if( !SCIProwIsInLP(consdata->row1) )
1717  {
1718  tmp = SCIPgetRowLPFeasibility(scip, consdata->row1);
1719  feasibility = MIN(feasibility, tmp);
1720  }
1721 
1722  /* check second row (setppc) for feasibility */
1723  if( !SCIProwIsInLP(consdata->row2) )
1724  {
1725  tmp = SCIPgetRowLPFeasibility(scip, consdata->row2);
1726  feasibility = MIN(feasibility, tmp);
1727  }
1728  addcut = SCIPisFeasNegative(scip, feasibility);
1729  }
1730  else
1731  addcut = !checkCons(scip, cons, sol);
1732 
1733 
1734  if( !addcut )
1735  {
1736  /* constraint was feasible -> increase age */
1737  SCIP_CALL( SCIPincConsAge(scip, cons) );
1738  }
1739  }
1740 
1741  if( addcut )
1742  {
1743  /* insert LP row as cut */
1744  assert(!(*cutoff));
1745  SCIP_CALL( addCuts(scip, cons, sol, cutoff) );
1746  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1747  *separated = TRUE;
1748  }
1749 
1750  return SCIP_OKAY;
1751 }
1752 
1753 /** enforces the pseudo solution on the given constraint */
1754 static
1756  SCIP* scip, /**< SCIP data structure */
1757  SCIP_CONS* cons, /**< linking constraint to be separated */
1758  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1759  SCIP_Bool* infeasible, /**< pointer to store TRUE, if the constraint was infeasible */
1760  int* nchgbds, /**< pointer to store the number of changed variable bounds */
1761  SCIP_Bool* solvelp /**< pointer to store TRUE, if the LP has to be solved */
1762  )
1763 {
1764  SCIP_Bool addcut;
1765  SCIP_Bool mustcheck;
1766 
1767  assert(!SCIPhasCurrentNodeLP(scip));
1768  assert(cons != NULL);
1769  assert(SCIPconsGetHdlr(cons) != NULL);
1770  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
1771  assert(cutoff != NULL);
1772  assert(infeasible != NULL);
1773  assert(nchgbds != NULL);
1774  assert(solvelp != NULL);
1775 
1776  addcut = FALSE;
1777  mustcheck = TRUE;
1778 
1779  /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
1780  SCIP_CALL( processIntegerBoundChg(scip, cons, cutoff, nchgbds, &mustcheck) );
1781  SCIP_CALL( processBinvarFixings(scip, cons, cutoff, nchgbds, &addcut, &mustcheck) );
1782 
1783  if( mustcheck )
1784  {
1785  assert(!addcut);
1786 
1787  if( checkCons(scip, cons, NULL) )
1788  {
1789  /* constraint was feasible -> increase age */
1790  SCIP_CALL( SCIPincConsAge(scip, cons) );
1791  }
1792  else
1793  {
1794  /* constraint was infeasible -> reset age */
1795  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1796  *infeasible = TRUE;
1797  }
1798  }
1799 
1800  if( addcut )
1801  {
1802  assert(!(*cutoff));
1803  /* a cut must be added to the LP -> we have to solve the LP immediately */
1804  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1805  *solvelp = TRUE;
1806  }
1807 
1808  return SCIP_OKAY;
1809 }
1810 
1811 
1812 /*
1813  * Callback methods of constraint handler
1814  */
1815 
1816 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
1817 static
1818 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyLinking)
1819 { /*lint --e{715}*/
1820  assert(scip != NULL);
1821  assert(conshdlr != NULL);
1822  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1823 
1824  /* call inclusion method of constraint handler */
1826 
1827  *valid = TRUE;
1828 
1829  return SCIP_OKAY;
1830 }
1831 
1832 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
1833 static
1834 SCIP_DECL_CONSFREE(consFreeLinking)
1835 {
1836  SCIP_CONSHDLRDATA* conshdlrdata;
1837 
1838  assert(conshdlr != NULL);
1839  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1840  assert(scip != NULL);
1841 
1842  /* free constraint handler data */
1843  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1844  assert(conshdlrdata != NULL);
1845 
1846  SCIP_CALL( conshdlrdataFree(scip, &conshdlrdata) );
1847 
1848  return SCIP_OKAY;
1849 }
1850 
1851 
1852 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
1853 static
1854 SCIP_DECL_CONSINITPRE(consInitpreLinking)
1855 { /*lint --e{715}*/
1856  SCIP_CONSHDLRDATA* conshdlrdata;
1857  SCIP_CONSDATA* consdata;
1858  int c;
1859 
1860  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1861  assert(conshdlrdata != NULL);
1862 
1863  /* disable all linking constraints which contain at most one binary variable */
1864  for( c = 0; c < nconss; ++c )
1865  {
1866  consdata = SCIPconsGetData(conss[c]);
1867  assert(consdata != NULL);
1868 
1869  /* skip constraints which are not added */
1870  if( !SCIPconsIsAdded(conss[c]) )
1871  continue;
1872 
1873  if( consdata->nbinvars <= 1 )
1874  {
1875  SCIP_CALL( SCIPdisableCons(scip, conss[c]) );
1876  assert(consdata->nbinvars == 0 || SCIPvarGetLbGlobal(consdata->binvars[0]) > 0.5);
1877  }
1878  else if( conshdlrdata->linearize )
1879  {
1880  SCIP_CALL( consdataLinearize(scip, conss[c], consdata) );
1881  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
1882  }
1883  }
1884 
1885  return SCIP_OKAY;
1886 }
1887 
1888 
1889 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
1890 static
1891 SCIP_DECL_CONSEXITSOL(consExitsolLinking)
1892 { /*lint --e{715}*/
1893  SCIP_CONSDATA* consdata;
1894  int c;
1895 
1896  for( c = 0; c < nconss; ++c )
1897  {
1898  consdata = SCIPconsGetData(conss[c]);
1899  assert(consdata != NULL);
1900 
1901  /* release the rows of all constraints */
1902  if( consdata->row1 != NULL )
1903  {
1904  assert(consdata->row2 != NULL);
1905 
1906  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row1) );
1907  SCIP_CALL( SCIPreleaseRow(scip, &consdata->row2) );
1908  }
1909  }
1910 
1911  return SCIP_OKAY;
1912 }
1913 
1914 
1915 /** frees specific constraint data */
1916 static
1917 SCIP_DECL_CONSDELETE(consDeleteLinking)
1918 { /*lint --e{715}*/
1919  SCIP_CONSHDLRDATA* conshdlrdata;
1920 
1921  assert(conshdlr != NULL);
1922  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1923  assert(consdata != NULL);
1924  assert(*consdata != NULL);
1925 
1926  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1927  assert(conshdlrdata != NULL);
1928  assert(conshdlrdata->eventhdlr != NULL);
1929 
1930  /* remove linking constraint form variable hash map */
1931  assert(conshdlrdata->varmap != NULL);
1932  assert(SCIPhashmapExists(conshdlrdata->varmap, getHashmapKey((*consdata)->intvar)));
1933  SCIP_CALL( SCIPhashmapRemove(conshdlrdata->varmap, getHashmapKey((*consdata)->intvar)) );
1934 
1935  if( (*consdata)->nbinvars > 0 && SCIPisTransformed(scip) )
1936  {
1937  SCIP_CALL( dropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
1938  }
1939 
1940  /* free consdata */
1941  SCIP_CALL( consdataFree(scip, consdata) );
1942 
1943  return SCIP_OKAY;
1944 }
1945 
1946 
1947 /** transforms constraint data into data belonging to the transformed problem */
1948 static
1949 SCIP_DECL_CONSTRANS(consTransLinking)
1950 { /*lint --e{715}*/
1951  SCIP_CONSDATA* sourcedata;
1952  SCIP_CONSDATA* targetdata;
1953  SCIP_CONSHDLRDATA* conshdlrdata;
1954 
1955  assert(conshdlr != NULL);
1956  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1957  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
1958  assert(sourcecons != NULL);
1959  assert(targetcons != NULL);
1960 
1961  /* free constraint handler data */
1962  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1963  assert(conshdlrdata != NULL);
1964  assert(conshdlrdata->eventhdlr != NULL);
1965 
1966  sourcedata = SCIPconsGetData(sourcecons);
1967  assert(sourcedata != NULL);
1968  assert(sourcedata->row1 == NULL); /* in original problem, there cannot be LP rows */
1969  assert(sourcedata->row2 == NULL); /* in original problem, there cannot be LP rows */
1970 
1971  SCIPdebugMessage("transform linking constraint for variable <%s>\n", SCIPvarGetName(sourcedata->intvar));
1972 
1973  /* create constraint data for target constraint */
1974  SCIP_CALL( consdataCreate(scip, conshdlrdata->eventhdlr, &targetdata,
1975  sourcedata->intvar, sourcedata->binvars, sourcedata->vals, sourcedata->nbinvars) );
1976 
1977  /* create target constraint */
1978  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
1979  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
1980  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
1981  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
1982  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
1983 
1984  /* insert (transformed) linking constraint into the hash map */
1985  assert(conshdlrdata->varmap != NULL);
1986  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varmap, getHashmapKey(targetdata->intvar), *targetcons) );
1987 
1988  return SCIP_OKAY;
1989 }
1990 
1991 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
1992 static
1993 SCIP_DECL_CONSINITLP(consInitlpLinking)
1994 { /*lint --e{715}*/
1995  SCIP_CONSDATA* consdata;
1996  SCIP_Bool cutoff;
1997  int c;
1998 
1999  for( c = 0; c < nconss; ++c )
2000  {
2001  assert(SCIPconsIsInitial(conss[c]));
2002 
2003  consdata = SCIPconsGetData(conss[c]);
2004  assert(consdata != NULL);
2005 
2006  if( consdata->nbinvars <= 1 )
2007  continue;
2008 
2009  /* ignore cutoff, cannot return value */
2010  SCIP_CALL( addCuts(scip, conss[c], NULL, &cutoff) );
2011  }
2012 
2013  return SCIP_OKAY;
2014 }
2015 
2016 
2017 /** separation method of constraint handler for LP solutions */
2018 static
2019 SCIP_DECL_CONSSEPALP(consSepalpLinking)
2020 { /*lint --e{715}*/
2021  SCIP_Bool cutoff;
2022  SCIP_Bool separated;
2023  int nchgbds;
2024  int c;
2025 
2026  assert(conshdlr != NULL);
2027  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2028  assert(nconss == 0 || conss != NULL);
2029  assert(result != NULL);
2030 
2031  SCIPdebugMessage("separating %d/%d linking constraints\n", nusefulconss, nconss);
2032 
2033  cutoff = FALSE;
2034  separated = FALSE;
2035  nchgbds = 0;
2036 
2037  /* check all useful linking constraints for feasibility */
2038  for( c = 0; c < nusefulconss && !cutoff; ++c )
2039  {
2040  SCIP_CALL( separateCons(scip, conss[c], NULL, &cutoff, &separated, &nchgbds) );
2041  }
2042 
2043  /* return the correct result */
2044  if( cutoff )
2045  *result = SCIP_CUTOFF;
2046  else if( nchgbds > 0 )
2047  *result = SCIP_REDUCEDDOM;
2048  else if( separated )
2049  *result = SCIP_SEPARATED;
2050  else
2051  *result = SCIP_DIDNOTFIND;
2052 
2053  return SCIP_OKAY;
2054 }
2055 
2056 
2057 /** separation method of constraint handler for arbitrary primal solutions */
2058 static
2059 SCIP_DECL_CONSSEPASOL(consSepasolLinking)
2060 { /*lint --e{715}*/
2061  SCIP_Bool cutoff;
2062  SCIP_Bool separated;
2063  int nchgbds;
2064  int c;
2065 
2066  assert(conshdlr != NULL);
2067  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2068  assert(nconss == 0 || conss != NULL);
2069  assert(result != NULL);
2070 
2071  SCIPdebugMessage("separating %d/%d "CONSHDLR_NAME" constraints\n", nusefulconss, nconss);
2072 
2073  cutoff = FALSE;
2074  separated = FALSE;
2075  nchgbds = 0;
2076 
2077  /* check all useful set partitioning / packing / covering constraints for feasibility */
2078  for( c = 0; c < nusefulconss && !cutoff; ++c )
2079  {
2080  SCIP_CALL( separateCons(scip, conss[c], sol, &cutoff, &separated, &nchgbds) );
2081  }
2082 
2083  /* return the correct result */
2084  if( cutoff )
2085  *result = SCIP_CUTOFF;
2086  else if( nchgbds > 0 )
2087  *result = SCIP_REDUCEDDOM;
2088  else if( separated )
2089  *result = SCIP_SEPARATED;
2090  else
2091  *result = SCIP_DIDNOTFIND;
2092 
2093  return SCIP_OKAY;
2094 }
2095 
2096 
2097 /** constraint enforcing method of constraint handler for LP solutions */
2098 static
2099 SCIP_DECL_CONSENFOLP(consEnfolpLinking)
2100 { /*lint --e{715}*/
2101  SCIP_Bool cutoff;
2102  SCIP_Bool separated;
2103  int nchgbds;
2104  int c;
2105 
2106  assert(conshdlr != NULL);
2107  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2108  assert(nconss == 0 || conss != NULL);
2109  assert(result != NULL);
2110 
2111  SCIPdebugMessage("LP enforcing %d linking constraints\n", nconss);
2112 
2113  cutoff = FALSE;
2114  separated = FALSE;
2115  nchgbds = 0;
2116 
2117  /* check all useful linking constraints for feasibility */
2118  for( c = 0; c < nusefulconss && !cutoff && nchgbds == 0; ++c )
2119  {
2120  SCIP_CALL( separateCons(scip, conss[c], NULL, &cutoff, &separated, &nchgbds) );
2121  }
2122 
2123  /* check all obsolete linking constraints for feasibility */
2124  for( c = nusefulconss; c < nconss && !cutoff && !separated && nchgbds == 0; ++c )
2125  {
2126  SCIP_CALL( separateCons(scip, conss[c], NULL, &cutoff, &separated, &nchgbds) );
2127  }
2128 
2129  /* return the correct result */
2130  if( cutoff )
2131  *result = SCIP_CUTOFF;
2132  else if( nchgbds > 0 )
2133  *result = SCIP_REDUCEDDOM;
2134  else if( separated )
2135  *result = SCIP_SEPARATED;
2136  else
2137  *result = SCIP_FEASIBLE;
2138 
2139  return SCIP_OKAY;
2140 }
2141 
2142 
2143 /** constraint enforcing method of constraint handler for pseudo solutions */
2144 static
2145 SCIP_DECL_CONSENFOPS(consEnfopsLinking)
2146 { /*lint --e{715}*/
2147  SCIP_Bool cutoff;
2148  SCIP_Bool infeasible;
2149  int nchgbds;
2150  SCIP_Bool solvelp;
2151  int c;
2152 
2153  assert(conshdlr != NULL);
2154  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2155  assert(nconss == 0 || conss != NULL);
2156  assert(result != NULL);
2157 
2158  SCIPdebugMessage("pseudo enforcing %d "CONSHDLR_NAME" constraints\n", nconss);
2159 
2160  if( objinfeasible )
2161  {
2162  *result = SCIP_DIDNOTRUN;
2163  return SCIP_OKAY;
2164  }
2165 
2166  cutoff = FALSE;
2167  infeasible = FALSE;
2168  nchgbds = 0;
2169  solvelp = FALSE;
2170 
2171  /* check all linking constraint for domain reductions and feasibility */
2172  for( c = 0; c < nconss && !cutoff && !solvelp; ++c )
2173  {
2174  SCIP_CALL( enforcePseudo(scip, conss[c], &cutoff, &infeasible, &nchgbds, &solvelp) );
2175  }
2176 
2177  if( cutoff )
2178  *result = SCIP_CUTOFF;
2179  else if( nchgbds > 0 )
2180  *result = SCIP_REDUCEDDOM;
2181  else if( solvelp )
2182  *result = SCIP_SOLVELP;
2183  else if( infeasible )
2184  *result = SCIP_INFEASIBLE;
2185  else
2186  *result = SCIP_FEASIBLE;
2187 
2188  return SCIP_OKAY;
2189 }
2190 
2191 
2192 /** feasibility check method of constraint handler for integral solutions */
2193 static
2194 SCIP_DECL_CONSCHECK(consCheckLinking)
2195 { /*lint --e{715}*/
2196  SCIP_CONS* cons;
2197  SCIP_CONSDATA* consdata;
2198  int c;
2199 
2200  assert(conshdlr != NULL);
2201  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2202  assert(nconss == 0 || conss != NULL);
2203  assert(result != NULL);
2204 
2205  *result = SCIP_FEASIBLE;
2206 
2207  /* check all linking constraints for feasibility */
2208  for( c = 0; c < nconss; ++c )
2209  {
2210  cons = conss[c];
2211  consdata = SCIPconsGetData(cons);
2212  assert(consdata != NULL);
2213 
2214  if( consdata->nbinvars > 1 && (checklprows || consdata->row1 == NULL || !SCIProwIsInLP(consdata->row1)) )
2215  {
2216  if( !checkCons(scip, cons, sol) )
2217  {
2218  /* constraint is violated */
2219  *result = SCIP_INFEASIBLE;
2220 
2221  if( printreason )
2222  {
2223  int pos;
2224  int b;
2225 
2226  pos = -1;
2227 
2228 #ifndef NDEBUG
2229  for( b = 0; b < consdata->nbinvars; ++b )
2230  {
2231  assert(consdata->binvars[b] != NULL);
2232  assert(SCIPvarIsBinary(consdata->binvars[b]));
2233  }
2234 #endif
2235 
2236  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2237  SCIPinfoMessage(scip, NULL, ";\n");
2238 
2239  /* check that at most one binary variable is fixed */
2240  for( b = 0; b < consdata->nbinvars; ++b )
2241  {
2242  assert( SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, consdata->binvars[b])) );
2243 
2244  /* check if binary variable is fixed */
2245  if( SCIPgetSolVal(scip, sol, consdata->binvars[b]) > 0.5 )
2246  {
2247  if( pos != -1 )
2248  {
2249  SCIPinfoMessage(scip, NULL, "violation: more than one binary variable is set to one");
2250  break;
2251  }
2252  pos = b ;
2253  }
2254  }
2255 
2256  /* check that at least one binary variable is fixed */
2257  if( pos == -1 )
2258  {
2259  SCIPinfoMessage(scip, NULL, "violation: none of the binary variables is set to one");
2260  }
2261  else if( !SCIPisFeasEQ(scip, (SCIP_Real) (consdata->vals[pos]), SCIPgetSolVal(scip, sol, consdata->intvar)) )
2262  {
2263  /* check if the fixed binary variable match with the integer variable */
2264  SCIPinfoMessage(scip, NULL, "violation: <%s> = <%g> and <%s> is one\n",
2265  SCIPvarGetName(consdata->intvar), SCIPgetSolVal(scip, sol, consdata->intvar),
2266  SCIPvarGetName(consdata->binvars[pos]) );
2267  }
2268  }
2269 
2270  break;
2271  }
2272  }
2273  }
2274 
2275  return SCIP_OKAY;
2276 }
2277 
2278 /** domain propagation method of constraint handler */
2279 static
2280 SCIP_DECL_CONSPROP(consPropLinking)
2281 { /*lint --e{715}*/
2282  SCIP_Bool cutoff;
2283  SCIP_Bool addcut;
2284  SCIP_Bool mustcheck;
2285  int nchgbds;
2286  int c;
2287 
2288  assert(conshdlr != NULL);
2289  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2290  assert(nconss == 0 || conss != NULL);
2291  assert(result != NULL);
2292 
2293  SCIPdebugMessage("propagating %d/%d "CONSHDLR_NAME" constraints\n", nusefulconss, nconss);
2294 
2295  cutoff = FALSE;
2296  nchgbds = 0;
2297  addcut = FALSE;
2298  mustcheck = TRUE;
2299 
2300  /* propagate all useful set partitioning / packing / covering constraints */
2301  for( c = 0; c < nusefulconss && !cutoff; ++c )
2302  {
2303  SCIP_CALL( processIntegerBoundChg(scip, conss[c], &cutoff, &nchgbds, &mustcheck) );
2304  SCIP_CALL( processBinvarFixings(scip, conss[c], &cutoff, &nchgbds, &addcut, &mustcheck) );
2305  }
2306 
2307  /* return the correct result */
2308  if( cutoff )
2309  *result = SCIP_CUTOFF;
2310  else if( nchgbds > 0 )
2311  *result = SCIP_REDUCEDDOM;
2312  else
2313  *result = SCIP_DIDNOTFIND;
2314 
2315  return SCIP_OKAY;
2316 }
2317 
2318 
2319 /** presolving method of constraint handler */
2320 static
2321 SCIP_DECL_CONSPRESOL(consPresolLinking)
2322 { /*lint --e{715}*/
2323  SCIP_CONSHDLRDATA* conshdlrdata;
2324  int oldnfixedvars;
2325  int oldnchgbds;
2326  int oldnaggrvars;
2327  int oldndelconss;
2328  int firstchange;
2329  int firstclique;
2330  int lastclique;
2331  int c;
2332  SCIP_Bool fixed;
2333  SCIP_Bool cutoff;
2334  SCIP_Bool infeasible;
2335  SCIP_Bool mustcheck;
2336 
2337  assert(conshdlr != NULL);
2338  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2339  assert(scip != NULL);
2340  assert(result != NULL);
2341 
2342  SCIPdebugMessage("presolve %d linking constraints\n", nconss);
2343 
2344  (*result) = SCIP_DIDNOTFIND;
2345 
2346  oldnchgbds = *nchgbds;
2347  oldnaggrvars = *naggrvars;
2348  oldnfixedvars = *nfixedvars;
2349  oldndelconss = *ndelconss;
2350  cutoff = FALSE;
2351 
2352  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2353  assert(conshdlrdata != NULL);
2354 
2355  /* process constraints */
2356  firstchange = INT_MAX;
2357  firstclique = INT_MAX;
2358  lastclique = -1;
2359 
2360  /* check for each linking constraint the set partitioning condition */
2361  for( c = 0; c < nconss && !SCIPisStopped(scip); ++c )
2362  {
2363  SCIP_CONS* cons;
2364  SCIP_CONSDATA* consdata;
2365 
2366  assert(*result != SCIP_CUTOFF);
2367 
2368  cons = conss[c];
2369  assert(cons != NULL);
2370  assert(!SCIPconsIsModifiable(cons));
2371 
2372  SCIPdebugMessage("presolve linking constraints <%s>\n", SCIPconsGetName(cons));
2373 
2374  consdata = SCIPconsGetData(cons);
2375  assert(consdata != NULL);
2376 
2377  if( !SCIPconsIsEnabled(cons) /* || consdata->nbinvars <= 1 */ )
2378  continue;
2379 
2380  /* in case there is only at most one binary variables, the constraints should already be disabled */
2381  assert(consdata->nbinvars > 1);
2382 
2383  /*SCIPdebugMessage("presolving set partitioning / packing / covering constraint <%s>\n", SCIPconsGetName(cons));*/
2384  if( consdata->nfixedones >= 2 )
2385  {
2386  /* at least two variables are fixed to 1:
2387  * - a linking constraint is infeasible due to the set partitioning condition
2388  */
2389  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s> is infeasible\n", SCIPconsGetName(cons));
2390  *result = SCIP_CUTOFF;
2391  return SCIP_OKAY;
2392  }
2393 
2394  if( consdata->nfixedones == 1 )
2395  {
2396  /* exactly one variable is fixed to 1:
2397  * - all other binary variables must be zero due to the set partitioning condition
2398  * - integer variable has to be fixed to corresponding binary variable which is fixed to one
2399  * - if constraint is not modifiable it can be removed
2400  */
2401  SCIP_VAR* var;
2402  int v;
2403 
2404  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s> has a binary variable fixed to 1.0\n", SCIPconsGetName(cons));
2405 
2406  for( v = 0; v < consdata->nbinvars; ++v )
2407  {
2408  var = consdata->binvars[v];
2409  assert(var != NULL);
2410 
2411  if( SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 )
2412  {
2413  SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
2414 
2415  if( infeasible )
2416  {
2417  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s>: infeasible fixing <%s> == 0\n",
2418  SCIPconsGetName(cons), SCIPvarGetName(var));
2419 
2420  *result = SCIP_CUTOFF;
2421  return SCIP_OKAY;
2422  }
2423  assert(fixed);
2424  (*nfixedvars)++;
2425  }
2426  else if( SCIPvarGetLbGlobal(var) > 0.5 )
2427  {
2428  /* fix integer variable */
2429  SCIP_CALL( SCIPfixVar(scip, consdata->intvar, (SCIP_Real)(consdata->vals[v]), &infeasible, &fixed) );
2430 
2431  if( infeasible )
2432  {
2433  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s>: infeasible fixing <%s> == %d\n",
2434  SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), consdata->vals[v]);
2435 
2436  *result = SCIP_CUTOFF;
2437  return SCIP_OKAY;
2438  }
2439 
2440  if( fixed )
2441  (*nfixedvars)++;
2442  }
2443  }
2444 
2445  /* now all other variables are fixed to zero:
2446  * the constraint is feasible, and if it's not modifiable, it is redundant
2447  */
2448  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s> is redundant\n", SCIPconsGetName(cons));
2449  SCIP_CALL( SCIPdelCons(scip, cons) );
2450  (*ndelconss)++;
2451  continue;
2452  }
2453 
2454  if( consdata->nfixedzeros == consdata->nbinvars )
2455  {
2456  /* all variables are fixed to zero:
2457  * - a linking constraint is infeasible due the set partitioning condition
2458  */
2459  assert(consdata->nfixedones == 0);
2460 
2461  SCIPdebugMessage("linking constraint <%s> is infeasible due to set partitioning condition\n", SCIPconsGetName(cons));
2462  *result = SCIP_CUTOFF;
2463  return SCIP_OKAY;
2464  }
2465 
2466  if( consdata->nfixedzeros == consdata->nbinvars - 1 )
2467  {
2468  /* all variables except one are fixed to zero:
2469  * - a linking constraint is feasible due the set partitioning condition
2470  * - the remaining binary variable can be fixed to one
2471  * - integer variable has to be fixed to corresponding binary variable which is fixed to one
2472  * - constraint can be deleted since it is not modifiable
2473  */
2474  SCIP_VAR* var;
2475  SCIP_Bool found;
2476  int v;
2477 
2478  assert(consdata->nfixedones == 0);
2479 
2480  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s> has only one binary variable not fixed to zero\n",
2481  SCIPconsGetName(cons));
2482 
2483  /* search unfixed variable */
2484  found = FALSE;
2485  var = NULL;
2486  for( v = 0; v < consdata->nbinvars && !found; ++v )
2487  {
2488  var = consdata->binvars[v];
2489  found = SCIPvarGetUbGlobal(var) > 0.5;
2490  }
2491  assert(found);
2492 
2493  /* fix remaining binary variable */
2494  SCIP_CALL( SCIPfixVar(scip, var, 1.0, &infeasible, &fixed) );
2495  if( infeasible )
2496  {
2497  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s>: infeasible fixing <%s> == 1\n",
2498  SCIPconsGetName(cons), SCIPvarGetName(var));
2499  *result = SCIP_CUTOFF;
2500  return SCIP_OKAY;
2501  }
2502  assert(fixed);
2503  (*nfixedvars)++;
2504 
2505  /* fix integer variable */
2506  SCIP_CALL( SCIPfixVar(scip, consdata->intvar, (SCIP_Real)(consdata->vals[v]), &infeasible, &fixed) );
2507  if( infeasible )
2508  {
2509  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s>: infeasible fixing <%s> == %d\n",
2510  SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), consdata->vals[v]);
2511 
2512  *result = SCIP_CUTOFF;
2513  return SCIP_OKAY;
2514  }
2515  assert(fixed);
2516  (*nfixedvars)++;
2517 
2518  /* delete constraint from problem */
2519  SCIP_CALL( SCIPdelCons(scip, cons) );
2520  (*ndelconss)++;
2521  continue;
2522  }
2523 
2524  if( consdata->nfixedzeros == consdata->nbinvars - 2 ) /*lint !e641*/
2525  {
2526  SCIP_VAR* var;
2527  SCIP_VAR* var1;
2528  SCIP_VAR* var2;
2529  SCIP_Bool redundant;
2530  SCIP_Bool aggregated;
2531  int v;
2532 
2533  /* aggregate variable, if set partitioning condition consists only of two
2534  * non-fixed variables
2535  */
2536 
2537  /* search unfixed variable */
2538  var1 = NULL;
2539  var2 = NULL;
2540  for( v = 0; v < consdata->nbinvars && var2 == NULL; ++v )
2541  {
2542  var = consdata->binvars[v];
2543  if( SCIPvarGetUbGlobal(var) > 0.5 )
2544  {
2545  if( var1 == NULL )
2546  var1 = var;
2547  else
2548  var2 = var;
2549  }
2550  }
2551  assert(var1 != NULL && var2 != NULL);
2552 
2553  /* aggregate binary equality var1 + var2 == 1 */
2554  SCIPdebugMessage(""CONSHDLR_NAME" constraint <%s>: aggregate <%s> + <%s> == 1\n",
2555  SCIPconsGetName(cons), SCIPvarGetName(var1), SCIPvarGetName(var2));
2556  SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
2557 
2558  /* evaluate aggregation result */
2559  if( infeasible )
2560  {
2561  SCIPdebugMessage("linking constraint <%s>: infeasible aggregation <%s> + <%s> == 1\n",
2562  SCIPconsGetName(cons), SCIPvarGetName(var1), SCIPvarGetName(var2));
2563  *result = SCIP_CUTOFF;
2564  return SCIP_OKAY;
2565  }
2566  if( aggregated )
2567  (*naggrvars)++;
2568  }
2569 
2570  /* apply integer bound to binary variables */
2571  SCIP_CALL( processIntegerBoundChg(scip, cons, &cutoff, nchgbds, &mustcheck) );
2572 
2573  /* tightened integer variable */
2574  SCIP_CALL( tightenedIntvar(scip, cons, consdata, &cutoff, nchgbds) );
2575 
2576  /* remove the trailing and leeading binary variable which are fixed to zero */
2577  SCIP_CALL( removeFixedBinvars(scip, conshdlrdata->eventhdlr, cons) );
2578 
2579  if( cutoff )
2580  {
2581  *result = SCIP_CUTOFF;
2582  return SCIP_OKAY;
2583  }
2584 
2585  /* remember the first changed constraint to begin the next redundancy round with */
2586  if( firstchange == INT_MAX )
2587  firstchange = c;
2588 
2589  /* remember the first and last constraints for which we have to add the clique information */
2590  if( !consdata->cliqueadded && consdata->nbinvars >= 2 )
2591  {
2592  if( firstclique == INT_MAX )
2593  firstclique = c;
2594  lastclique = c;
2595  }
2596  }
2597 
2598  /* add clique and implication information */
2599  for( c = firstclique; c < lastclique && !SCIPisStopped(scip); ++c )
2600  {
2601  SCIP_CONS* cons;
2602  SCIP_CONSDATA* consdata;
2603 
2604  assert(*result != SCIP_CUTOFF);
2605 
2606  cons = conss[c];
2607  assert(cons != NULL);
2608 
2609  /* ignore deleted constraints */
2610  if( !SCIPconsIsActive(cons) )
2611  continue;
2612 
2613  consdata = SCIPconsGetData(cons);
2614  assert(consdata != NULL);
2615 
2616  if( !consdata->cliqueadded && consdata->nbinvars >= 3 )
2617  {
2618  /* add set partitioning condition as clique */
2619  int ncliquebdchgs;
2620 
2621  SCIP_CALL( SCIPaddClique(scip, consdata->binvars, NULL, consdata->nbinvars, &infeasible, &ncliquebdchgs) );
2622  *nchgbds += ncliquebdchgs;
2623 
2624  if( infeasible )
2625  {
2626  *result = SCIP_CUTOFF;
2627  return SCIP_OKAY;
2628  }
2629 
2630  consdata->cliqueadded = TRUE;
2631  }
2632  }
2633 
2634 #if 0
2635  /* transfer aggregated integer variables to the corresponding binary variables */
2636  assert(conshdlrdata->varmap != NULL);
2637  SCIP_CALL( aggregateVariables(scip, conshdlrdata->varmap, conss, nconss, naggrvars, &cutoff) );
2638 #endif
2639 
2640  if( cutoff )
2641  *result = SCIP_CUTOFF;
2642  else if( oldndelconss < *ndelconss || oldnfixedvars < *nfixedvars || oldnchgbds < *nchgbds || oldnaggrvars < *naggrvars)
2643  *result = SCIP_SUCCESS;
2644 
2645  return SCIP_OKAY;
2646 }
2647 
2648 
2649 /** propagation conflict resolving method of constraint handler */
2650 static
2651 SCIP_DECL_CONSRESPROP(consRespropLinking)
2652 { /*lint --e{715}*/
2653 
2654  SCIP_CONSDATA* consdata;
2655  SCIP_VAR* intvar;
2656  int v;
2657 
2658  SCIPdebugMessage("conflict resolving method of "CONSHDLR_NAME" constraint handler\n");
2659 
2660  consdata = SCIPconsGetData(cons);
2661  assert(consdata != NULL);
2662 
2663  intvar = consdata->intvar;
2664  assert( intvar != NULL);
2665 
2666  *result = SCIP_DIDNOTFIND;
2667 
2668  if( inferinfo == -1 )
2669  {
2670  /* we have to resolve a fixing of a binary variable which was done due to fixed binary variables */
2671  assert(SCIPvarIsBinary(infervar));
2672  assert(SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetUbAtIndex(intvar, bdchgidx, FALSE)));
2673  assert(SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetLbAtIndex(intvar, bdchgidx, FALSE)));
2674 
2675  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2676  {
2677  /* we fixed the binary variable to zero since one of the other binary variable was fixed to one (set
2678  * partitioning condition)
2679  */
2680  assert(SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE) < 0.5);
2681 
2682  for( v = 0; v < consdata->nbinvars; ++v )
2683  {
2684  if( SCIPvarGetLbAtIndex(consdata->binvars[v], bdchgidx, FALSE) > 0.5 )
2685  {
2686  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvars[v]) );
2687  break;
2688  }
2689  }
2690  assert(v < consdata->nbinvars);
2691  }
2692  else
2693  {
2694  /* we fixed the binary variable to one since all other binary variable were fixed to zero */
2695  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2696  assert(SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE) > 0.5);
2697 
2698  for( v = 0; v < consdata->nbinvars; ++v )
2699  {
2700  if( consdata->binvars[v] != infervar )
2701  {
2702  /* the reason variable must be assigned to zero */
2703  assert(SCIPvarGetUbAtIndex(consdata->binvars[v], bdchgidx, FALSE) < 0.5);
2704  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvars[v]) );
2705  }
2706  }
2707  }
2708  }
2709  else if( inferinfo == -2 )
2710  {
2711  /* we have to resolve a fixing of a binary variable which was done due to the integer variable lower bound */
2712  assert(SCIPvarIsBinary(infervar));
2713  assert(SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE) < 0.5);
2714  assert(SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE) < 0.5); /*@repair: neu*/
2715  assert(SCIPvarGetUbAtIndex(infervar, bdchgidx, FALSE) > 0.5); /*@repair: neu*/
2716  assert( SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetUbAtIndex(intvar, bdchgidx, FALSE)) );
2717  assert( SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetLbAtIndex(intvar, bdchgidx, FALSE)) );
2718 
2719 
2720  SCIP_CALL( SCIPaddConflictLb( scip, intvar, bdchgidx) );
2721  }
2722  else if( inferinfo == -3 )
2723  {
2724  /* we have to resolve a fixing of a binary variable which was done due to the integer variable upper bound */
2725  assert(SCIPvarIsBinary(infervar));
2726  assert(SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE) < 0.5);
2727  assert(SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE) < 0.5);
2728  assert(SCIPvarGetUbAtIndex(infervar, bdchgidx, FALSE) > 0.5);
2729  assert( SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetUbAtIndex(intvar, bdchgidx, FALSE)) );
2730  assert( SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetLbAtIndex(intvar, bdchgidx, FALSE)) );
2731 
2732  SCIP_CALL( SCIPaddConflictUb( scip, intvar, bdchgidx) );
2733  }
2734  else if( inferinfo == -4 )
2735  {
2736  SCIP_VAR** binvars;
2737  int* vals;
2738  int nbinvars;
2739  int lb;
2740  int b;
2741 
2742  /* we tightened the lower bound of the integer variable due the fixing of the corresponding binary variable to zero */
2743  assert(infervar == intvar);
2744  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2745 
2746  binvars = consdata->binvars;
2747  nbinvars = consdata->nbinvars;
2748  vals = consdata->vals;
2749 
2750  /* get propagated lower bound */
2751  lb = (int)(SCIPvarGetLbAtIndex(intvar, bdchgidx, TRUE) + 0.5);
2752 
2753  for( b = 0; b < nbinvars; ++b )
2754  {
2755  if( vals[b] >= lb )
2756  break;
2757 
2758  assert(SCIPvarGetUbLocal(binvars[b]) < 0.5);
2759  SCIP_CALL( SCIPaddConflictBinvar(scip, binvars[b]) );
2760  }
2761  }
2762  else if( inferinfo == -5 )
2763  {
2764  SCIP_VAR** binvars;
2765  int* vals;
2766  int nbinvars;
2767  int ub;
2768  int b;
2769 
2770  /* we tightened the upper bound of the integer variable due the fixing of the corresponding binary variable two zero */
2771 
2772  assert(infervar == intvar);
2773  assert(boundtype == SCIP_BOUNDTYPE_UPPER);
2774 
2775  binvars = consdata->binvars;
2776  nbinvars = consdata->nbinvars;
2777  vals = consdata->vals;
2778 
2779  /* get old and new upper bound */
2780  ub = (int)(SCIPvarGetUbAtIndex(intvar, bdchgidx, TRUE) + 0.5);
2781 
2782  /* resolve tightening of upper bound of the integer variable by binary variables */
2783  for( b = nbinvars - 1; b >= 0; --b )
2784  {
2785  if( vals[b] <= ub )
2786  break;
2787 
2788  assert(SCIPvarGetUbLocal(binvars[b]) < 0.5);
2789  SCIP_CALL( SCIPaddConflictBinvar(scip, binvars[b]) );
2790  }
2791  }
2792  else if( inferinfo == -6 )
2793  {
2794  /* we fixed a binary variable to one since the integer variable was fixed */
2795  assert(SCIPvarIsBinary(infervar));
2796  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2797  assert( SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetUbAtIndex(intvar, bdchgidx, FALSE)) );
2798  assert( SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetUbAtIndex(intvar, bdchgidx, FALSE)) );
2799  assert( SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetLbAtIndex(intvar, bdchgidx, FALSE)) );
2800  assert( SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(intvar, bdchgidx, TRUE), SCIPvarGetLbAtIndex(intvar, bdchgidx, FALSE)) );
2801 
2802  assert( !SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE), SCIPvarGetLbAtIndex(infervar, bdchgidx, FALSE)) );
2803 
2804  SCIP_CALL( SCIPaddConflictLb( scip, intvar, bdchgidx) );
2805  SCIP_CALL( SCIPaddConflictUb( scip, intvar, bdchgidx) );
2806  }
2807  else
2808  {
2809  /* we fixed the integer variable to (vals[inferinfo]) since the corresponding binary variable was fixed to one */
2810  assert(infervar == intvar);
2811  assert(inferinfo >= 0);
2812  assert(inferinfo < consdata->nbinvars);
2813  assert(consdata->vals[inferinfo] == (int)(SCIPvarGetUbAtIndex(consdata->intvar, bdchgidx, TRUE) + 0.5)
2814  || consdata->vals[inferinfo] == (int)(SCIPvarGetLbAtIndex(consdata->intvar, bdchgidx, TRUE) + 0.5));
2815 
2816  assert(SCIPvarGetLbAtIndex(consdata->binvars[inferinfo], bdchgidx, FALSE) > 0.5);
2817  SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->binvars[inferinfo]) );
2818  }
2819 
2820  *result = SCIP_SUCCESS;
2821 
2822  return SCIP_OKAY;
2823 }
2824 
2825 /** variable rounding lock method of constraint handler */
2826 static
2827 SCIP_DECL_CONSLOCK(consLockLinking)
2828 { /*lint --e{715}*/
2829  SCIP_CONSDATA* consdata;
2830  int b;
2831 
2832  consdata = SCIPconsGetData(cons);
2833  assert(consdata != NULL);
2834 
2835  /* look integer variable in both directions */
2836  SCIP_CALL( SCIPaddVarLocks(scip, consdata->intvar, nlockspos + nlocksneg, nlockspos + nlocksneg) );
2837 
2838  /* look binary variables in both directions */
2839  for( b = 0; b < consdata->nbinvars; ++b )
2840  {
2841  SCIP_CALL( SCIPaddVarLocks(scip, consdata->binvars[b], nlockspos + nlocksneg, nlockspos + nlocksneg) );
2842  }
2843 
2844  return SCIP_OKAY;
2845 }
2846 
2847 /** constraint enabling notification method of constraint handler */
2848 static
2849 SCIP_DECL_CONSENABLE(consEnableLinking)
2850 { /*lint --e{715}*/
2851 #if 0
2852  SCIP_CONSHDLRDATA* conshdlrdata;
2853  SCIP_CONSDATA* consdata;
2854 
2855  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2856  assert(conshdlrdata != NULL);
2857 
2858  consdata = SCIPconsGetData(cons);
2859  assert(consdata != NULL);
2860 
2861  if( consdata->nbinvars <= 1 )
2862  {
2863  SCIP_CALL( SCIPdisableCons(scip, cons) );
2864  assert(consdata->nbinvars == 0 || SCIPvarGetLbGlobal(consdata->binvars[0]) > 0.5);
2865  }
2866  else if( conshdlrdata->linearize )
2867  {
2868  SCIP_CALL( consdataLinearize(scip, cons, consdata) );
2869  SCIP_CALL( SCIPdelCons(scip, cons) );
2870  }
2871 #endif
2872  return SCIP_OKAY;
2873 }
2874 
2875 /** constraint display method of constraint handler */
2876 static
2877 SCIP_DECL_CONSPRINT(consPrintLinking)
2878 { /*lint --e{715}*/
2879  assert(scip != NULL);
2880  assert(conshdlr != NULL);
2881  assert(cons != NULL);
2882 
2883  SCIP_CALL( consdataPrint(scip, SCIPconsGetData(cons), file) );
2884 
2885  return SCIP_OKAY;
2886 }
2887 
2888 
2889 /** constraint copying method of constraint handler */
2890 static
2891 SCIP_DECL_CONSCOPY(consCopyLinking)
2892 { /*lint --e{715}*/
2893  SCIP_CONSDATA* sourceconsdata;
2894  SCIP_VAR** binvars;
2895  SCIP_VAR* intvar;
2896  int* vals;
2897  const char* consname;
2898  int nbinvars;
2899  int v;
2900 
2901  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) != 0 )
2902  {
2903  SCIPerrorMessage("constraint is not a linking constraint\n");
2904  SCIPABORT();
2905  return SCIP_INVALIDDATA; /*lint !e527*/
2906  }
2907 
2908  (*valid) = TRUE;
2909 
2910  sourceconsdata = SCIPconsGetData(sourcecons);
2911  assert(sourceconsdata != NULL);
2912 
2913  /* get number of binary variables, integer variables */
2914  nbinvars = sourceconsdata->nbinvars;
2915  intvar = sourceconsdata->intvar;
2916 
2917  /* duplicate variable array */
2918  if( nbinvars > 0 )
2919  {
2920  SCIP_CALL( SCIPduplicateBufferArray(scip, &binvars, sourceconsdata->binvars, nbinvars) );
2921  SCIP_CALL( SCIPduplicateBufferArray(scip, &vals, sourceconsdata->vals, nbinvars) );
2922  }
2923  else
2924  {
2925  binvars = NULL;
2926  vals = NULL;
2927  }
2928 
2929  /* get copy for the binary variables */
2930  for( v = 0; v < nbinvars && *valid; ++v )
2931  {
2932  assert(binvars != NULL); /* for flexelint */
2933  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, binvars[v], &binvars[v], varmap, consmap, global, valid) );
2934  assert(!(*valid) || binvars[v] != NULL);
2935  }
2936 
2937  /* copy the integer variable */
2938  if( *valid )
2939  {
2940  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, intvar, &intvar, varmap, consmap, global, valid) );
2941  assert(!(*valid) || intvar != NULL);
2942  }
2943 
2944  /* only create the target constraint, if all variables could be copied */
2945  if( *valid )
2946  {
2947  if( name != NULL )
2948  consname = name;
2949  else
2950  consname = SCIPconsGetName(sourcecons);
2951 
2952  SCIP_CALL( SCIPcreateConsLinking(scip, cons, consname, intvar, binvars, vals, nbinvars,
2953  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
2954  }
2955 
2956  /* free buffer array */
2957  if( nbinvars > 0 )
2958  {
2959  SCIPfreeBufferArrayNull(scip, &vals);
2960  SCIPfreeBufferArrayNull(scip, &binvars);
2961  }
2962 
2963  return SCIP_OKAY;
2964 }
2965 
2966 /** constraint parsing method of constraint handler */
2967 static
2968 SCIP_DECL_CONSPARSE(consParseLinking)
2969 { /*lint --e{715}*/
2970  SCIP_VAR** binvars;
2971  SCIP_VAR* intvar;
2972  int* intvals;
2973  char* endptr;
2974  int varssize;
2975  int nbinvars;
2976 
2977  assert(scip != NULL);
2978  assert(success != NULL);
2979  assert(str != NULL);
2980  assert(name != NULL);
2981  assert(cons != NULL);
2982 
2983  *success = TRUE;
2984 
2985  /* parse integer variables */
2986  SCIP_CALL( SCIPparseVarName(scip, str, &intvar, &endptr) );
2987 
2988  if( intvar == NULL )
2989  {
2990  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
2991  *success = FALSE;
2992  return SCIP_OKAY;
2993  }
2994  str = endptr;
2995 
2996  nbinvars = 0;
2997  varssize = 16;
2998 
2999  SCIP_CALL( SCIPallocBufferArray(scip, &binvars, varssize) );
3000  SCIP_CALL( SCIPallocBufferArray(scip, &intvals, varssize) );
3001 
3002  while( *str != '=' )
3003  ++str;
3004 
3005  /* skip '=' */
3006  ++str;
3007 
3008  /* skip whitespace */
3009  while( isspace((int)*str) )
3010  ++str;
3011 
3012  /* check for the string "no binary variables yet" */
3013  if( strncmp(str, "no binary variables yet", 24) != 0 )
3014  {
3015  SCIP_Real* vals;
3016  int requsize;
3017  int v;
3018 
3019  SCIP_CALL( SCIPallocBufferArray(scip, &vals, varssize) );
3020 
3021  /* parse linear sum to get variables and coefficients */
3022  SCIP_CALL( SCIPparseVarsLinearsum(scip, str, binvars, vals, &nbinvars, varssize, &requsize, &endptr, success) );
3023 
3024  if( *success && requsize > varssize )
3025  {
3026  /* realloc buffers and try again */
3027  varssize = requsize;
3028  SCIP_CALL( SCIPreallocBufferArray(scip, &binvars, varssize) );
3029  SCIP_CALL( SCIPreallocBufferArray(scip, &intvals, varssize) );
3030  SCIP_CALL( SCIPreallocBufferArray(scip, &vals, varssize) );
3031 
3032  SCIP_CALL( SCIPparseVarsLinearsum(scip, str, binvars, vals, &nbinvars, varssize, &requsize, &endptr, success) );
3033  assert(!*success || requsize <= varssize); /* if successful, then should have had enough space now */
3034  }
3035 
3036  /* check coefficients */
3037  if( *success )
3038  {
3039  /* convert SCIP_Real to integer */
3040  for( v = 0; v < nbinvars; ++v )
3041  {
3042  assert(SCIPisIntegral(scip, vals[v]));
3043 
3044  /* check that the coefficients is integral */
3045  *success = *success && SCIPisIntegral(scip, vals[v]);
3046 
3047  if( vals[v] < 0 )
3048  intvals[v] = (int)(vals[v] - 0.5);
3049  else
3050  intvals[v] = (int)(vals[v] + 0.5);
3051  }
3052  }
3053 
3054  SCIPfreeBufferArray(scip, &vals);
3055  }
3056 
3057  if( *success )
3058  {
3059  SCIP_CALL( SCIPcreateConsLinking(scip, cons, name, intvar, binvars, intvals, nbinvars,
3060  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3061  }
3062 
3063  SCIPfreeBufferArray(scip, &intvals);
3064  SCIPfreeBufferArray(scip, &binvars);
3065 
3066  return SCIP_OKAY;
3067 }
3068 
3069 /** constraint method of constraint handler which returns the variables (if possible) */
3070 static
3071 SCIP_DECL_CONSGETVARS(consGetVarsLinking)
3072 { /*lint --e{715}*/
3073  SCIP_CONSDATA* consdata;
3074 
3075  consdata = SCIPconsGetData(cons);
3076  assert(consdata != NULL);
3077 
3078  if( varssize < consdata->nbinvars + 1)
3079  (*success) = FALSE;
3080  else
3081  {
3082  assert(vars != NULL);
3083 
3084  BMScopyMemoryArray(vars, consdata->binvars, consdata->nbinvars);
3085  vars[consdata->nbinvars] = consdata->intvar;
3086  (*success) = TRUE;
3087  }
3088 
3089  return SCIP_OKAY;
3090 }
3091 
3092 /** constraint method of constraint handler which returns the number of variables (if possible) */
3093 static
3094 SCIP_DECL_CONSGETNVARS(consGetNVarsLinking)
3095 { /*lint --e{715}*/
3096  SCIP_CONSDATA* consdata;
3097 
3098  consdata = SCIPconsGetData(cons);
3099  assert(consdata != NULL);
3100 
3101  (*nvars) = consdata->nbinvars + 1;
3102  (*success) = TRUE;
3103 
3104  return SCIP_OKAY;
3105 }
3106 
3107 /*
3108  * Callback methods of event handler
3109  */
3110 
3111 /** execution method of event handler */
3112 static
3113 SCIP_DECL_EVENTEXEC(eventExecBinvar)
3114 { /*lint --e{715}*/
3115  SCIP_CONSDATA* consdata;
3116  SCIP_EVENTTYPE eventtype;
3117 
3118  assert(eventhdlr != NULL);
3119  assert(eventdata != NULL);
3120  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
3121  assert(event != NULL);
3122 
3123  consdata = (SCIP_CONSDATA*)eventdata;
3124  assert(consdata != NULL);
3125 
3126  eventtype = SCIPeventGetType(event);
3127  switch( eventtype )
3128  {
3130  consdata->nfixedones++;
3131  break;
3133  consdata->nfixedones--;
3134  consdata->firstnonfixed = 0;
3135  consdata->lastnonfixed = consdata->nbinvars - 1;
3136  break;
3138  consdata->nfixedzeros++;
3139  break;
3141  consdata->firstnonfixed = 0;
3142  consdata->lastnonfixed = consdata->nbinvars - 1;
3143  consdata->nfixedzeros--;
3144  break;
3145  default:
3146  SCIPerrorMessage("invalid event type\n");
3147  return SCIP_INVALIDDATA;
3148  }
3149  assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nbinvars);
3150  assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nbinvars);
3151 
3152  /*debugMessage(" -> constraint has %d zero-fixed and %d one-fixed of %d variables\n",
3153  consdata->nfixedzeros, consdata->nfixedones, consdata->nvars);*/
3154 
3155  return SCIP_OKAY;
3156 }
3157 
3158 /*
3159  * constraint specific interface methods
3160  */
3161 
3162 /** creates the handler for linking constraints and includes it in SCIP */
3164  SCIP* scip /**< SCIP data structure */
3165  )
3166 {
3167  SCIP_CONSHDLRDATA* conshdlrdata;
3168  SCIP_CONSHDLR* conshdlr;
3169  SCIP_EVENTHDLR* eventhdlr;
3170 
3171  /* create event handler for bound change events */
3173  eventExecBinvar, NULL) );
3174 
3175  /* create linking constraint handler data */
3176  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
3177 
3178  /* include constraint handler */
3181  consEnfolpLinking, consEnfopsLinking, consCheckLinking, consLockLinking,
3182  conshdlrdata) );
3183 
3184  assert(conshdlr != NULL);
3185 
3186  /* set non-fundamental callbacks via specific setter functions */
3187  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyLinking, consCopyLinking) );
3188  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteLinking) );
3189  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableLinking) );
3190  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolLinking) );
3191  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeLinking) );
3192  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsLinking) );
3193  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsLinking) );
3194  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreLinking) );
3195  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpLinking) );
3196  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseLinking) );
3197  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolLinking, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
3198  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintLinking) );
3199  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropLinking, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
3201  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropLinking) );
3202  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpLinking, consSepasolLinking, CONSHDLR_SEPAFREQ,
3204  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransLinking) );
3205 
3206 
3207  /* include the linear constraint to linking constraint upgrade in the linear constraint handler */
3208  /* SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdLinking, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) ); */
3209 
3210  /* add linking constraint handler parameters */
3212  "constraints/"CONSHDLR_NAME"/linearize", "this constraint will not propagate or separate, linear and setppc are used?",
3213  &conshdlrdata->linearize, FALSE, DEFAULT_LINEARIZE, NULL, NULL) );
3214 
3215  return SCIP_OKAY;
3216 }
3217 
3218 /** creates and captures a linking constraint
3219  *
3220  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
3221  */
3223  SCIP* scip, /**< SCIP data structure */
3224  SCIP_CONS** cons, /**< pointer to hold the created constraint */
3225  const char* name, /**< name of constraint */
3226  SCIP_VAR* intvar, /**< integer variable which should be linked */
3227  SCIP_VAR** binvars, /**< binary variables, or NULL */
3228  int* vals, /**< coefficients of the binary variables */
3229  int nbinvars, /**< number of binary variables */
3230  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3231  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3232  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3233  * Usually set to TRUE. */
3234  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3235  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3236  SCIP_Bool check, /**< should the constraint be checked for feasibility?
3237  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3238  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3239  * Usually set to TRUE. */
3240  SCIP_Bool local, /**< is constraint only valid locally?
3241  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3242  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
3243  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
3244  * adds coefficients to this constraint. */
3245  SCIP_Bool dynamic, /**< is constraint subject to aging?
3246  * Usually set to FALSE. Set to TRUE for own cuts which
3247  * are separated as constraints. */
3248  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3249  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3250  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3251  * if it may be moved to a more global node?
3252  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3253  )
3254 {
3255  SCIP_CONSHDLR* conshdlr;
3256  SCIP_CONSDATA* consdata;
3257  SCIP_CONSHDLRDATA* conshdlrdata;
3258 
3259  assert(scip != NULL);
3260  assert(!SCIPisInfinity(scip, -SCIPvarGetLbGlobal(intvar)));
3261  assert(!SCIPisInfinity(scip, SCIPvarGetUbGlobal(intvar)));
3262 
3263  /* find the linking constraint handler */
3264  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3265  if( conshdlr == NULL )
3266  {
3267  SCIPerrorMessage("linking constraint handler not found\n");
3268  return SCIP_PLUGINNOTFOUND;
3269  }
3270 
3271  SCIPdebugMessage("create linking constraint for variable <%s> with %d binary variable (SCIP stage %d)\n",
3272  SCIPvarGetName(intvar), nbinvars, SCIPgetStage(scip));
3273 
3274  /* get constraint handler data */
3275  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3276  assert(conshdlrdata != NULL);
3277 
3278  if( conshdlrdata->varmap == NULL )
3279  {
3280  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varmap, SCIPblkmem(scip), HASHSIZE_BINVARSCONS) );
3281  }
3282  assert(conshdlrdata->varmap != NULL);
3283 
3284  /* check if the linking for the requests integer variable already exists */
3285  assert(!SCIPhashmapExists(conshdlrdata->varmap, getHashmapKey(intvar)));
3286 
3287  /* create the constraint specific data */
3288  SCIP_CALL( consdataCreate(scip, conshdlrdata->eventhdlr, &consdata, intvar, binvars, vals, nbinvars) );
3289 
3290  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
3291  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3292 
3293  /* insert linking constraint into the hash map */
3294  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varmap, getHashmapKey(intvar), *cons) );
3295  assert(SCIPhashmapExists(conshdlrdata->varmap, getHashmapKey(intvar)));
3296 
3297  return SCIP_OKAY;
3298 }
3299 
3300 /** creates and captures a linking constraint
3301  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
3302  * method SCIPcreateConsLinking(); all flags can be set via SCIPsetCons<Flagname>-methods in scip.h
3303  *
3304  * @see SCIPcreateConsLinking() for information about the basic constraint flag configuration
3305  *
3306  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
3307  */
3309  SCIP* scip, /**< SCIP data structure */
3310  SCIP_CONS** cons, /**< pointer to hold the created constraint */
3311  const char* name, /**< name of constraint */
3312  SCIP_VAR* intvar, /**< integer variable which should be linked */
3313  SCIP_VAR** binvars, /**< binary variables, or NULL */
3314  int* vals, /**< coefficients of the binary variables */
3315  int nbinvars /**< number of binary variables */
3316  )
3317 {
3318  assert(scip != NULL);
3319 
3320  SCIP_CALL( SCIPcreateConsLinking(scip, cons, name, intvar, binvars, vals, nbinvars,
3321  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
3322 
3323  return SCIP_OKAY;
3324 }
3325 
3326 /** checks if for the given integer variable a linking constraint exists */
3328  SCIP* scip, /**< SCIP data structure */
3329  SCIP_VAR* intvar /**< integer variable which should be linked */
3330  )
3331 {
3332  SCIP_CONSHDLR* conshdlr;
3333  SCIP_CONSHDLRDATA* conshdlrdata;
3334 
3335  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3336  assert(conshdlr != NULL);
3337 
3338  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3339  assert(conshdlrdata != NULL);
3340 
3341  return (conshdlrdata->varmap != NULL) && SCIPhashmapExists(conshdlrdata->varmap, getHashmapKey(intvar));
3342 }
3343 
3344 /** returns the linking constraint belonging to the given integer variable or NULL if it does not exist yet */
3346  SCIP* scip, /**< SCIP data structure */
3347  SCIP_VAR* intvar /**< integer variable which should be linked */
3348  )
3349 {
3350  SCIP_CONSHDLR* conshdlr;
3351  SCIP_CONSHDLRDATA* conshdlrdata;
3352 
3353  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3354  assert(conshdlr != NULL);
3355 
3356  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3357  assert(conshdlrdata != NULL);
3358 
3359  if( conshdlrdata->varmap != NULL )
3360  return (SCIP_CONS*) SCIPhashmapGetImage(conshdlrdata->varmap, getHashmapKey(intvar));
3361  else
3362  return NULL;
3363 }
3364 
3365 /** returns the integer variable of the linking constraint */
3367  SCIP* scip, /**< SCIP data structure */
3368  SCIP_CONS* cons /**< linking constraint */
3369  )
3370 {
3371  SCIP_CONSDATA* consdata;
3372 
3373  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
3374  {
3375  SCIPerrorMessage("constraint is not a "CONSHDLR_NAME" constraint\n");
3376  SCIPABORT();
3377  return NULL; /*lint !e527*/
3378  }
3379 
3380  consdata = SCIPconsGetData(cons);
3381  assert(consdata != NULL);
3382 
3383  return consdata->intvar;
3384 
3385 }
3386 
3387 /** returns the binary variables of the linking constraint */
3389  SCIP* scip, /**< SCIP data structure */
3390  SCIP_CONS* cons, /**< linking constraint */
3391  SCIP_VAR*** binvars, /**< pointer to store the binary variables array pointer */
3392  int* nbinvars /**< pointer to store the number of returned binary variables */
3393  )
3394 {
3395  SCIP_CONSDATA* consdata;
3396 
3397  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
3398  {
3399  SCIPerrorMessage("constraint is not a "CONSHDLR_NAME" constraint\n");
3400  SCIPABORT();
3401  return SCIP_INVALIDDATA; /*lint !e527*/
3402  }
3403 
3404  consdata = SCIPconsGetData(cons);
3405  assert(consdata != NULL);
3406 
3407  if( consdata->binvars == NULL )
3408  {
3409  SCIP_CONSHDLR* conshdlr;
3410  SCIP_CONSHDLRDATA* conshdlrdata;
3411 
3412  conshdlr = SCIPconsGetHdlr(cons);
3413  assert(conshdlr != NULL);
3414 
3415  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3416  assert(conshdlrdata != NULL);
3417 
3418  SCIP_CALL( consdataCreateBinvars(scip, cons, consdata, conshdlrdata->eventhdlr, conshdlrdata->linearize) );
3419  }
3420 
3421  assert(consdata->binvars != NULL);
3422 
3423  if( binvars != NULL )
3424  (*binvars) = consdata->binvars;
3425  if( nbinvars != NULL )
3426  (*nbinvars) = consdata->nbinvars;
3427 
3428  return SCIP_OKAY;
3429 }
3430 
3431 /** returns the number of binary variables of the linking constraint */
3433  SCIP* scip, /**< SCIP data structure */
3434  SCIP_CONS* cons /**< linking constraint */
3435  )
3436 {
3437  SCIP_CONSDATA* consdata;
3438 
3439  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
3440  {
3441  SCIPerrorMessage("constraint is not a "CONSHDLR_NAME" constraint\n");
3442  SCIPABORT();
3443  return -1; /*lint !e527*/
3444  }
3445 
3446  consdata = SCIPconsGetData(cons);
3447  assert(consdata != NULL);
3448 
3449  return consdata->nbinvars;
3450 }
3451 
3452 /** returns the coefficients of the binary variables */
3454  SCIP* scip, /**< SCIP data structure */
3455  SCIP_CONS* cons /**< linking constraint */
3456  )
3457 {
3458  SCIP_CONSDATA* consdata;
3459 
3460  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
3461  {
3462  SCIPerrorMessage("constraint is not a "CONSHDLR_NAME" constraint\n");
3463  SCIPABORT();
3464  return NULL; /*lint !e527*/
3465  }
3466 
3467  consdata = SCIPconsGetData(cons);
3468  assert(consdata != NULL);
3469  assert(consdata->sorted);
3470 
3471  return consdata->vals;
3472 }
3473