Scippy

SCIP

Solving Constraint Integer Programs

presol_gateextraction.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 presol_gateextraction.c
17  * @brief gateextraction presolver
18  * @author Michael Winkler
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 #include <string.h>
25 
27 #include "scip/cons_setppc.h"
28 #include "scip/cons_logicor.h"
29 #include "scip/cons_and.h"
30 
31 
32 #define PRESOL_NAME "gateextraction"
33 #define PRESOL_DESC "presolver extracting gate(and)-constraints"
34 #define PRESOL_PRIORITY 1000000 /**< priority of the presolver (>= 0: before, < 0: after constraint handlers); combined with propagators */
35 #define PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
36 #define PRESOL_DELAY TRUE /**< should presolver be delayed, if other presolvers found reductions? */
37 
38 #define HASHSIZE_LOGICORCONS 131101 /**< minimal size of hash table in logicor constraint tables */
39 #define HASHSIZE_SETPPCCONS 131101 /**< minimal size of hash table in setppc constraint tables */
40 
41 #define DEFAULT_ONLYSETPART FALSE /**< should only set-partitioning constraints be extracted and no and-constraints */
42 #define DEFAULT_SEARCHEQUATIONS TRUE /**< should we try to extract set-partitioning constraint out of one logicor
43  * and one corresponding set-packing constraint
44  */
45 #define DEFAULT_SORTING 1 /**< order logicor contraints to extract big-gates before smaller ones (-1), do
46  * not order them (0) or order them to extract smaller gates at first (1)
47  */
48 
49 
50 /* This presolver tries to extract gate-constraints meaning and-constraints and set-partitioning constraints (and could
51  * be expanded to find xor-constraints too). This is done by detecting linearizations or systems of inequalities which
52  * form an and-constraint or a set-partitioning constraint. An example:
53  *
54  * we have a logicor constraint of the form: x + y + z >= 1
55  *
56  * and we also have the following set-packing constraints: (x + y <= 1 and x + z <= 1) <=> (~x + ~y >= 1 and ~x + ~z >= 1)
57  *
58  * - these three constraints form an and-constraint: x = ~y * ~z (x = AND(~y,~z))
59  *
60  * if an additional set-packing constraint exists: y + z <= 1
61  *
62  * - these four constraints form a set-partitioning cons.: x + y + z = 1
63  *
64  * some information can be found:
65  *
66  * http://www.cs.ubc.ca/~hutter/earg/papers07/cnf-structure.pdf
67  * http://www.cadence.com/cn/cadence/cadence_labs/Documents/niklas_SAT_2005_Effective.pdf
68  *
69  * We also do some check for logicor and set-packing/-partitioning constraint with the same variables to upgrade these
70  * both constraints into one. For example:
71  *
72  * x + y + z >= 1 and x + y + z <= 1 form x + y + z = 1
73  *
74  */
75 
76 
77 /*
78  * Data structures
79  */
80 
81 
82 /** data object to compare constraint easier */
83 struct HashData
84 {
85  SCIP_CONS* cons; /**< pointer the the corresponding constraint */
86  SCIP_VAR** vars; /**< constraint variables used for hash comparison */
87  int nvars; /**< number of variables */
88 };
89 typedef struct HashData HASHDATA;
90 
91 
92 /** presolver data */
93 struct SCIP_PresolData
94 {
95  HASHDATA** setppchashdatas; /**< setppc-hashdata array pointing to the storage */
96  HASHDATA* setppchashdatastore;/**< setppc-hashdata storage */
97  SCIP_HASHTABLE* hashdatatable; /**< setppc-hashdata hashtable for usable setppc constraints */
98  SCIP_HASHTABLE* setppchashtable; /**< setppc hashtable for usable setppc constraints */
99  SCIP_HASHTABLE* logicorhashtable; /**< logicor hashtable for usable logicor constraints */
100  SCIP_CONS** usefullogicor; /**< array for usable logicors */
101  int nusefullogicor; /**< number of usable logicors */
102  int susefullogicor; /**< size of array for usable logicor constraints */
103  int nsetppchashdatas; /**< number of setppchashdata elements added to the hashtable */
104  int ssetppchashdatas; /**< size of setppchashdata elements added to the hashtable */
105  int ngates; /**< number of found gates in presolving */
106  int firstchangedlogicor;/**< position of the first new/changed logicor constraint in the
107  * usefullogicor array
108  */
109  int maxnvarslogicor; /**< maximal number of variables a logicor constraint has */
110  int sorting; /**< integer parameter how to sort logicor constraints for extracting
111  * gates
112  */
113  SCIP_Bool usefulsetppcexist; /**< did we find usable set-packing constraints for gate extraction */
114  SCIP_Bool usefullogicorexist; /**< did we find usable logicor constraints for gate extraction */
115  SCIP_Bool newsetppchashdatas; /**< flag indicating whether we found new set-packing constraint with two
116  * variables since the last presolving round
117  */
118  SCIP_Bool initialized; /**< was data alredy be initialized */
119  SCIP_Bool onlysetpart; /**< boolean parameter whetehr we only want to extract linear gates */
120  SCIP_Bool searchequations; /**< boolean parameter whetehr we want to search for equations arising from
121  * logicor and setppc constraints
122  */
123 };
124 
125 
126 /*
127  * Local methods
128  */
129 
130 
131 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same pointer */
132 static
133 SCIP_DECL_HASHKEYEQ(hashdataKeyEqCons)
134 {
135 #ifndef NDEBUG
136  SCIP* scip;
137 #endif
138  HASHDATA* hashdata1;
139  HASHDATA* hashdata2;
140  int v;
141 
142  hashdata1 = (HASHDATA*)key1;
143  hashdata2 = (HASHDATA*)key2;
144 #ifndef NDEBUG
145  scip = (SCIP*)userptr;
146  assert(scip != NULL);
147 #endif
148 
149  /* check data structure */
150  assert(hashdata1->nvars == 2);
151  assert(hashdata2->nvars == 2);
152  /* at least one data object needs to be have a real set packing constraint */
153  assert(hashdata1->cons != NULL || hashdata2->cons != NULL);
154 
155  for( v = 1; v >= 0; --v )
156  {
157  /* tests if variables are equal */
158  if( hashdata1->vars[v] != hashdata2->vars[v] )
159  return FALSE;
160 
161  assert(SCIPvarCompare(hashdata1->vars[v], hashdata2->vars[v]) == 0);
162  }
163 
164  /* a hashdata object is only equal if it has the same constraint pointer, or one has no constraint pointer, latter
165  * means that this hashdata object is derived from a logicor constraint
166  */
167  if( hashdata1->cons == NULL || hashdata2->cons == NULL || hashdata1->cons == hashdata2->cons )
168  return TRUE;
169  else
170  return FALSE;
171 }
172 
173 /** returns the hash value of the key */
174 static
175 SCIP_DECL_HASHKEYVAL(hashdataKeyValCons)
176 { /*lint --e{715}*/
177  HASHDATA* hashdata;
178  unsigned int hashval;
179 
180  hashdata = (HASHDATA*)key;
181  assert(hashdata != NULL);
182  assert(hashdata->vars != NULL);
183  assert(hashdata->nvars == 2);
184 
185  /* if we have only two variables we store at each 16 bits of the hash value the index of a variable */
186  hashval = (SCIPvarGetIndex(hashdata->vars[1]) << 16) + SCIPvarGetIndex(hashdata->vars[0]); /*lint !e701*/
187 
188  return hashval;
189 }
190 
191 
192 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same pointer */
193 static
194 SCIP_DECL_HASHKEYEQ(setppcHashdataKeyEqCons)
195 {
196 #ifndef NDEBUG
197  SCIP* scip;
198 #endif
199  HASHDATA* hashdata1;
200  HASHDATA* hashdata2;
201  int v;
202 
203  hashdata1 = (HASHDATA*)key1;
204  hashdata2 = (HASHDATA*)key2;
205 #ifndef NDEBUG
206  scip = (SCIP*)userptr;
207  assert(scip != NULL);
208 #endif
209 
210  /* check data structure */
211  assert(hashdata1->nvars >= 2);
212  assert(hashdata2->nvars >= 2);
213  /* at least one data object needs to be have a real set-packing/partitioning constraint */
214  assert(hashdata1->cons != NULL || hashdata2->cons != NULL);
215 
216  if( hashdata1->nvars != hashdata2->nvars )
217  return FALSE;
218 
219  for( v = hashdata1->nvars - 1; v >= 0; --v )
220  {
221  /* tests if variables are equal */
222  if( hashdata1->vars[v] != hashdata2->vars[v] )
223  return FALSE;
224 
225  assert(SCIPvarCompare(hashdata1->vars[v], hashdata2->vars[v]) == 0);
226  }
227 
228  /* a hashdata object is only equal if it has the same constraint pointer, or one has no constraint pointer, latter
229  * means that this hashdata object is derived from a logicor constraint
230  */
231  if( hashdata1->cons == NULL || hashdata2->cons == NULL || hashdata1->cons == hashdata2->cons )
232  return TRUE;
233  else
234  return FALSE;
235 }
236 
237 /** returns the hash value of the key */
238 static
239 SCIP_DECL_HASHKEYVAL(setppcHashdataKeyValCons)
240 { /*lint --e{715}*/
241  HASHDATA* hashdata;
242  unsigned int hashval;
243  int v;
244 
245  hashdata = (HASHDATA*)key;
246  assert(hashdata != NULL);
247  assert(hashdata->vars != NULL);
248  assert(hashdata->nvars >= 2);
249 
250  hashval = 0;
251 
252  /* if we have more then one variables the index of each variable is imaged to a bit positioned from 0 to 31, and over
253  * all variables these bitfields are combined by an or operation to get a good hashvalue for distinguishing the datas
254  */
255  for( v = 1; v >= 0; --v )
256  hashval |= (1 << (SCIPvarGetIndex(hashdata->vars[v]) % 32)); /*lint !e701*/
257 
258  return hashval;
259 }
260 
261 /** initialize gateextraction presolver data */
262 static
264  SCIP_PRESOLDATA* presoldata /**< data object of presolver */
265  )
266 {
267  assert(presoldata != NULL);
268 
269  presoldata->usefullogicor = NULL;
270  presoldata->nusefullogicor = 0;
271  presoldata->susefullogicor = 0;
272  presoldata->firstchangedlogicor = -1;
273  presoldata->maxnvarslogicor = 0;;
274  presoldata->nsetppchashdatas = 0;
275  presoldata->ssetppchashdatas = 0;
276  presoldata->ngates = 0;
277  presoldata->usefulsetppcexist = FALSE;
278  presoldata->usefullogicorexist = FALSE;
279  presoldata->newsetppchashdatas = FALSE;
280  presoldata->initialized = FALSE;
281 
282  presoldata->hashdatatable = NULL;
283  presoldata->setppchashtable = NULL;
284  presoldata->logicorhashtable = NULL;
285 }
286 
287 /** initialize gateextraction hashtables */
288 static
290  SCIP* scip, /**< SCIP data structure */
291  SCIP_PRESOLDATA* presoldata /**< data object of presolver */
292  )
293 {
294  assert(scip != NULL);
295  assert(presoldata != NULL);
296 
297  assert(presoldata->nusefullogicor == 0);
298  assert(presoldata->susefullogicor == 0);
299  assert(presoldata->nsetppchashdatas == 0);
300  assert(presoldata->ssetppchashdatas == 0);
301  assert(presoldata->firstchangedlogicor == -1);
302  assert(presoldata->ngates == 0);
303  assert(presoldata->usefullogicorexist == FALSE);
304  assert(presoldata->usefulsetppcexist == FALSE);
305  assert(presoldata->newsetppchashdatas == FALSE);
306  assert(presoldata->initialized == FALSE);
307 
308  assert(presoldata->hashdatatable == NULL);
309  assert(presoldata->setppchashtable == NULL);
310  assert(presoldata->logicorhashtable == NULL);
311 
312  /* create hashtables */
313  SCIP_CALL( SCIPhashtableCreate(&(presoldata->hashdatatable), SCIPblkmem(scip), HASHSIZE_SETPPCCONS, SCIPhashGetKeyStandard, hashdataKeyEqCons, hashdataKeyValCons, (void*) scip) );
314  SCIP_CALL( SCIPhashtableCreate(&(presoldata->setppchashtable), SCIPblkmem(scip), HASHSIZE_SETPPCCONS, SCIPhashGetKeyStandard, SCIPhashKeyEqPtr, SCIPhashKeyValPtr, (void*) scip) );
315  SCIP_CALL( SCIPhashtableCreate(&(presoldata->logicorhashtable), SCIPblkmem(scip), HASHSIZE_LOGICORCONS, SCIPhashGetKeyStandard, SCIPhashKeyEqPtr, SCIPhashKeyValPtr, (void*) scip) );
316 
317  return SCIP_OKAY;
318 }
319 
320 
321 /** create useful set-packing information by adding new set-packing constraints with two variables */
322 static
324  SCIP* scip, /**< SCIP data structure */
325  SCIP_PRESOLDATA* presoldata, /**< data object of presolver */
326  SCIP_CONS** setppcs, /**< active setppc constraints */
327  int nsetppcs, /**< number of active setppc constraints */
328  SCIP_CONS** logicors, /**< active logicor constraints */
329  int nlogicors /**< number of active logicor constraints */
330  )
331 {
332  SCIP_CONS** usefulconss;
333  int nusefulconss = 0;
334  int size;
335  int c;
336 
337  assert(scip != NULL);
338  assert(presoldata != NULL);
339  assert(setppcs != NULL);
340  assert(nsetppcs > 0);
341  assert(logicors != NULL);
342  assert(nlogicors > 0);
343  assert(presoldata->setppchashtable != NULL);
344  assert(presoldata->logicorhashtable != NULL);
345 
346  presoldata->initialized = TRUE;
347 
348  size = MAX(nsetppcs, nlogicors);
349 
350  /* temporary memory for collecting set-packing constraints */
351  SCIP_CALL( SCIPallocBufferArray(scip, &usefulconss, size) );
352 
353  if( !presoldata->usefulsetppcexist )
354  {
355  /* find set-packing constraints with exactly two varibales */
356  for( c = 0; c < nsetppcs; ++c )
357  {
358  assert(SCIPconsIsActive(setppcs[c]));
359 
360  if( SCIPgetTypeSetppc(scip, setppcs[c]) == SCIP_SETPPCTYPE_PACKING && SCIPgetNVarsSetppc(scip, setppcs[c]) == 2 && !SCIPconsIsModifiable(setppcs[c]) )
361  {
362  /* insert new element in hashtable */
363  SCIP_CALL( SCIPhashtableInsert(presoldata->setppchashtable, (void*) setppcs[c]) );
364 
365  usefulconss[nusefulconss] = setppcs[c];
366  ++nusefulconss;
367  }
368  }
369 
370  /* add usefulconss constraints to hashdata elements */
371  if( nusefulconss > 0 )
372  {
373  SCIP_Bool negated[2];
374  int h;
375 
376  presoldata->usefulsetppcexist = TRUE;
377  presoldata->ssetppchashdatas = nusefulconss;
378 
379  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(presoldata->setppchashdatas), nusefulconss) );
380  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(presoldata->setppchashdatastore), nusefulconss) );
381 
382  h = 0;
383  for( c = 0; c < nusefulconss; ++c )
384  {
385  assert(SCIPconsIsActive(usefulconss[c]));
386  assert(SCIPgetNVarsSetppc(scip, usefulconss[c]) == 2);
387  presoldata->setppchashdatas[h] = &(presoldata->setppchashdatastore[h]);
388 
389  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(presoldata->setppchashdatas[h]->vars), SCIPgetVarsSetppc(scip, usefulconss[c]), 2) );
390 
391  SCIP_CALL( SCIPgetBinvarRepresentative(scip, presoldata->setppchashdatas[h]->vars[0], &(presoldata->setppchashdatas[h]->vars[0]), &(negated[0])) );
392  SCIP_CALL( SCIPgetBinvarRepresentative(scip, presoldata->setppchashdatas[h]->vars[1], &(presoldata->setppchashdatas[h]->vars[1]), &(negated[1])) );
393 
394  if( SCIPvarGetStatus(presoldata->setppchashdatas[h]->vars[0]) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(presoldata->setppchashdatas[h]->vars[0]) == SCIP_VARSTATUS_MULTAGGR
395  || SCIPvarGetStatus(presoldata->setppchashdatas[h]->vars[1]) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(presoldata->setppchashdatas[h]->vars[1]) == SCIP_VARSTATUS_MULTAGGR )
396  {
397  SCIPfreeBlockMemoryArray(scip, &(presoldata->setppchashdatas[h]->vars), 2);
398  continue;
399  }
400 
401  presoldata->setppchashdatas[h]->nvars = 2;
402 
403  /* capture variables */
404  SCIP_CALL( SCIPcaptureVar(scip, presoldata->setppchashdatas[h]->vars[0]) );
405  SCIP_CALL( SCIPcaptureVar(scip, presoldata->setppchashdatas[h]->vars[1]) );
406 
407  /* order the variables after their index */
408  if( SCIPvarGetIndex(presoldata->setppchashdatas[h]->vars[0]) > SCIPvarGetIndex(presoldata->setppchashdatas[h]->vars[1]) )
409  {
410  SCIP_VAR* tmp = presoldata->setppchashdatas[h]->vars[0];
411  presoldata->setppchashdatas[h]->vars[0] = presoldata->setppchashdatas[h]->vars[1];
412  presoldata->setppchashdatas[h]->vars[1] = tmp;
413  }
414 
415  presoldata->setppchashdatas[h]->cons = usefulconss[c];
416 
417  SCIP_CALL( SCIPhashtableInsert(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[h]) );
418  SCIP_CALL( SCIPcaptureCons(scip, usefulconss[c]) );
419 
420  ++h;
421  }
422  presoldata->nsetppchashdatas = h;
423 
424  if( presoldata->nsetppchashdatas > 0 )
425  presoldata->newsetppchashdatas = TRUE;
426  }
427  }
428 
429  nusefulconss = 0;
430 
431  if( !presoldata->usefullogicorexist )
432  {
433  /* capture all logicor constraints */
434  for( c = 0; c < nlogicors; ++c )
435  {
436  assert(SCIPconsIsActive(logicors[c]));
437 
438  if( !SCIPconsIsModifiable(logicors[c]) && SCIPgetNVarsLogicor(scip, logicors[c]) >= 3 )
439  {
440  /* insert new element in hashtable */
441  SCIP_CALL( SCIPhashtableInsert(presoldata->logicorhashtable, (void*) logicors[c]) );
442  SCIP_CALL( SCIPcaptureCons(scip, logicors[c]) );
443 
444  usefulconss[nusefulconss] = logicors[c];
445  ++nusefulconss;
446 
447  /* update maximal entries in a logicor constraint */
448  if( presoldata->maxnvarslogicor < SCIPgetNVarsLogicor(scip, logicors[c]) )
449  presoldata->maxnvarslogicor = SCIPgetNVarsLogicor(scip, logicors[c]);
450  }
451  }
452 
453  /* no usefulconss constraints */
454  if( nusefulconss > 0 )
455  {
456  presoldata->firstchangedlogicor = 0;
457  presoldata->usefullogicorexist = TRUE;
458  presoldata->susefullogicor = nusefulconss;
459  presoldata->nusefullogicor = nusefulconss;
460  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &presoldata->usefullogicor, usefulconss, presoldata->susefullogicor) );
461  }
462  }
463 
464  /* free temporary memory */
465  SCIPfreeBufferArray(scip, &usefulconss);
466 
467  return SCIP_OKAY;
468 }
469 
470 
471 /** remove old setppchashdatas objects, so that the allocated memory will stay low */
472 static
474  SCIP* scip, /**< SCIP data structure */
475  SCIP_PRESOLDATA* presoldata /**< data object of presolver */
476  )
477 {
478  assert(scip != NULL);
479  assert(presoldata != NULL);
480 
481  if( presoldata->usefulsetppcexist )
482  {
483  int c;
484 
485  assert(presoldata->setppchashdatas != NULL || presoldata->nsetppchashdatas == 0);
486 
487  for( c = presoldata->nsetppchashdatas - 1; c >= 0; --c )
488  {
489  SCIP_Bool removeentry = FALSE;
490 
491  assert(presoldata->setppchashdatas[c] != NULL);
492  assert(presoldata->setppchashdatas[c]->cons != NULL);
493 
494  if( SCIPconsIsDeleted(presoldata->setppchashdatas[c]->cons) || SCIPconsIsModifiable(presoldata->setppchashdatas[c]->cons)
495  || SCIPgetTypeSetppc(scip, presoldata->setppchashdatas[c]->cons) != SCIP_SETPPCTYPE_PACKING || SCIPgetNVarsSetppc(scip, presoldata->setppchashdatas[c]->cons) != 2 )
496  {
497  removeentry = TRUE;
498  }
499  else
500  {
501  SCIP_VAR* vars[2];
502  SCIP_Bool negated[2];
503 
504  SCIP_CALL( SCIPgetBinvarRepresentative(scip, presoldata->setppchashdatas[c]->vars[0], &(vars[0]), &(negated[0])) );
505  SCIP_CALL( SCIPgetBinvarRepresentative(scip, presoldata->setppchashdatas[c]->vars[1], &(vars[1]), &(negated[1])) );
506 
509  || presoldata->setppchashdatas[c]->vars[0] != vars[0] || presoldata->setppchashdatas[c]->vars[1] != vars[1] )
510  {
511  removeentry = TRUE;
512  }
513  }
514 
515  if( removeentry )
516  {
517  /* remove constraint from setppc-hashtable */
518  assert(SCIPhashtableExists(presoldata->setppchashtable, (void*) presoldata->setppchashdatas[c]->cons));
519  SCIP_CALL( SCIPhashtableRemove(presoldata->setppchashtable, (void*) presoldata->setppchashdatas[c]->cons) );
520 
521  /* remove hashdata entry from hashtable */
522  SCIP_CALL( SCIPhashtableRemove(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[c]) );
523 
524  /* release old constraints */
525  SCIP_CALL( SCIPreleaseCons(scip, &(presoldata->setppchashdatas[c]->cons)) );
526 
527  /* release variables */
528  SCIP_CALL( SCIPreleaseVar(scip, &(presoldata->setppchashdatas[c]->vars[0])) );
529  SCIP_CALL( SCIPreleaseVar(scip, &(presoldata->setppchashdatas[c]->vars[1])) );
530 
531  /* free memory for variables */
532  SCIPfreeBlockMemoryArray(scip, &(presoldata->setppchashdatas[c]->vars), 2);
533 
534  if( c < presoldata->nsetppchashdatas - 1 )
535  {
536  /* remove old hashdata entry from hashtable */
537  SCIP_CALL( SCIPhashtableRemove(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[presoldata->nsetppchashdatas - 1]) );
538  }
539 
540  /* move last content to free position */
541  presoldata->setppchashdatas[c]->cons = presoldata->setppchashdatas[presoldata->nsetppchashdatas - 1]->cons;
542  presoldata->setppchashdatas[c]->vars = presoldata->setppchashdatas[presoldata->nsetppchashdatas - 1]->vars;
543  presoldata->setppchashdatas[c]->nvars = presoldata->setppchashdatas[presoldata->nsetppchashdatas - 1]->nvars;
544 
545  if( c < presoldata->nsetppchashdatas - 1 )
546  {
547  /* add new hashdata entry from hashtable */
548  SCIP_CALL( SCIPhashtableInsert(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[c]) );
549  }
550  --(presoldata->nsetppchashdatas);
551  }
552  }
553 
554 #ifndef NDEBUG
555  for( c = presoldata->nsetppchashdatas - 1; c >= 0; --c )
556  {
557  assert(presoldata->setppchashdatas[c] != NULL);
558  assert(presoldata->setppchashdatas[c]->nvars == 2);
559  assert(presoldata->setppchashdatas[c]->vars != NULL);
560  assert(presoldata->setppchashdatas[c]->vars[0] != NULL);
561  assert(presoldata->setppchashdatas[c]->vars[1] != NULL);
562  assert(presoldata->setppchashdatas[c]->cons != NULL);
563  assert(SCIPconsIsActive(presoldata->setppchashdatas[c]->cons));
564  assert(SCIPhashtableExists(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[c]));
565  assert(SCIPhashtableExists(presoldata->setppchashtable, (void*) presoldata->setppchashdatas[c]->cons));
566  }
567 #endif
568  }
569 
570  return SCIP_OKAY;
571 }
572 
573 /** refresh useful set-packing information, delete redundant constraints and add new constraints */
574 static
576  SCIP* scip, /**< SCIP data structure */
577  SCIP_PRESOLDATA* presoldata, /**< data object of presolver */
578  SCIP_CONS** setppcs, /**< active setppc constraints */
579  int nsetppcs, /**< number of active setppc constraints */
580  SCIP_CONS** logicors, /**< active setppc constraints */
581  int nlogicors /**< number of active setppc constraints */
582  )
583 {
584  int oldnsetppchashdatas;
585  int c;
586 
587  assert(scip != NULL);
588  assert(presoldata != NULL);
589  assert(setppcs != NULL);
590  assert(nsetppcs > 0);
591  assert(logicors != NULL);
592  assert(nlogicors > 0);
593  assert(presoldata->initialized);
594  assert(presoldata->setppchashtable != NULL);
595  assert(presoldata->logicorhashtable != NULL);
596 
597  /* check if there already exist some set-packing and some logicor constraints with the right amount of variables */
598  if( !presoldata->usefulsetppcexist || !presoldata->usefullogicorexist )
599  {
600  SCIP_Bool usefullogicorexisted = presoldata->usefullogicorexist;
601 
602  SCIP_CALL( createPresoldata(scip, presoldata, setppcs, nsetppcs, logicors, nlogicors) );
603 
604  /* if we already had useful logicor constraints but did not find any useful setppc constraint, the maximal number
605  * of variables appearing in a logicor constraint was not updated, so we do it here
606  */
607  if( usefullogicorexisted && !presoldata->usefulsetppcexist )
608  {
609  /* correct maximal number of varables in logicor constraints */
610  for( c = nlogicors - 1; c >= 0; --c )
611  {
612  assert(SCIPconsIsActive(logicors[c]));
613 
614  /* update maximal entries in a logicor constraint */
615  if( presoldata->maxnvarslogicor < SCIPgetNVarsLogicor(scip, logicors[c]) )
616  presoldata->maxnvarslogicor = SCIPgetNVarsLogicor(scip, logicors[c]);
617  }
618  }
619 
620  /* no correct logicor or set-packing constraints available, so abort */
621  if( !presoldata->usefulsetppcexist || !presoldata->usefullogicorexist )
622  return SCIP_OKAY;
623  }
624 
625  /* correct old data */
626  SCIP_CALL( cleanupHashDatas(scip, presoldata) );
627 
628  oldnsetppchashdatas = presoldata->nsetppchashdatas;
629 
630  /* first update setppc part */
631  /* add new setppc constraints */
632  for( c = nsetppcs - 1; c >= 0; --c )
633  {
634  assert(SCIPconsIsActive(setppcs[c]));
635 
636  if( SCIPgetTypeSetppc(scip, setppcs[c]) == SCIP_SETPPCTYPE_PACKING && SCIPgetNVarsSetppc(scip, setppcs[c]) == 2 && !SCIPconsIsModifiable(setppcs[c]) )
637  {
638  /* check if constraint is new, and correct array size if necessary */
639  if( !SCIPhashtableExists(presoldata->setppchashtable, (void*) setppcs[c]) )
640  {
641  SCIP_Bool negated[2];
642 
643  /* resize array if necessary */
644  if( presoldata->nsetppchashdatas == presoldata->ssetppchashdatas )
645  {
646  int newsize;
647  int d;
648 
649  newsize = SCIPcalcMemGrowSize(scip, presoldata->nsetppchashdatas + 1);
650 
651  /* array already at maximal size */
652  if( newsize <= presoldata->ssetppchashdatas )
653  return SCIP_NOMEMORY;
654 
655  /* correct hashtable, remove old elements */
656  SCIPhashtableRemoveAll(presoldata->hashdatatable);
657 
658  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(presoldata->setppchashdatas), presoldata->ssetppchashdatas, newsize) );
659  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(presoldata->setppchashdatastore), presoldata->ssetppchashdatas, newsize) );
660  presoldata->ssetppchashdatas = newsize;
661 
662  /* correct pointers in array, to point to the new storage, due to allocation, and add all elements to the
663  * hashtable again
664  */
665  for( d = presoldata->nsetppchashdatas - 1; d >= 0; --d )
666  {
667  presoldata->setppchashdatas[d] = &(presoldata->setppchashdatastore[d]);
668  SCIP_CALL( SCIPhashtableInsert(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[d]) );
669  }
670  }
671 
672  /* insert new element in hashtable */
673  SCIP_CALL( SCIPhashtableInsert(presoldata->setppchashtable, (void*) setppcs[c]) );
674 
675  assert(SCIPgetNVarsSetppc(scip, setppcs[c]) == 2);
676  presoldata->setppchashdatas[presoldata->nsetppchashdatas] = &(presoldata->setppchashdatastore[presoldata->nsetppchashdatas]);
677 
678  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars), SCIPgetVarsSetppc(scip, setppcs[c]), 2) );
679  SCIP_CALL( SCIPgetBinvarRepresentative(scip, presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0], &(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0]), &(negated[0])) );
680  SCIP_CALL( SCIPgetBinvarRepresentative(scip, presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1], &(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1]), &(negated[1])) );
681 
682  if( SCIPvarGetStatus(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0]) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0]) == SCIP_VARSTATUS_MULTAGGR
683  || SCIPvarGetStatus(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1]) == SCIP_VARSTATUS_FIXED || SCIPvarGetStatus(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1]) == SCIP_VARSTATUS_MULTAGGR )
684  {
685  SCIPfreeBlockMemoryArray(scip, &(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars), 2);
686  continue;
687  }
688 
689  presoldata->setppchashdatas[presoldata->nsetppchashdatas]->nvars = 2;
690 
691  /* capture variables */
692  SCIP_CALL( SCIPcaptureVar(scip, presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0]) );
693  SCIP_CALL( SCIPcaptureVar(scip, presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1]) );
694 
695  /* order the variables after their index */
696  if( SCIPvarGetIndex(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0]) > SCIPvarGetIndex(presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1]) )
697  {
698  SCIP_VAR* tmp = presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0];
699  presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[0] = presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1];
700  presoldata->setppchashdatas[presoldata->nsetppchashdatas]->vars[1] = tmp;
701  }
702 
703  presoldata->setppchashdatas[presoldata->nsetppchashdatas]->cons = setppcs[c];
704 
705  SCIP_CALL( SCIPhashtableInsert(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[presoldata->nsetppchashdatas]) );
706  SCIP_CALL( SCIPcaptureCons(scip, setppcs[c]) );
707 
708  ++(presoldata->nsetppchashdatas);
709  }
710  }
711  }
712 
713  /* if we found new set-packing constraints, we want to check against all logicors */
714  if( oldnsetppchashdatas < presoldata->nsetppchashdatas )
715  presoldata->newsetppchashdatas = TRUE;
716 
717  /* now logicor part */
718  /* removed last deleted logicor constraints from local presolver data */
719  while( presoldata->nusefullogicor > 0 && !SCIPconsIsActive(presoldata->usefullogicor[presoldata->nusefullogicor - 1]) )
720  {
721  SCIP_CALL( SCIPhashtableRemove(presoldata->logicorhashtable, (void*) presoldata->usefullogicor[presoldata->nusefullogicor - 1]) );
722  SCIP_CALL( SCIPreleaseCons(scip, &(presoldata->usefullogicor[presoldata->nusefullogicor - 1])) );
723 
724  --(presoldata->nusefullogicor);
725  }
726 
727  /* remove old inactive logicor constraints */
728  for( c = presoldata->nusefullogicor - 1; c >= 0; --c )
729  {
730  /* update maximal entries in a logicor constraint */
731  if( presoldata->maxnvarslogicor < SCIPgetNVarsLogicor(scip, presoldata->usefullogicor[c]) )
732  presoldata->maxnvarslogicor = SCIPgetNVarsLogicor(scip, presoldata->usefullogicor[c]);
733 
734  if( !SCIPconsIsActive(presoldata->usefullogicor[c]) || SCIPconsIsModifiable(presoldata->usefullogicor[c]) || SCIPgetNVarsLogicor(scip, presoldata->usefullogicor[c]) < 3 )
735  {
736  SCIP_CALL( SCIPhashtableRemove(presoldata->logicorhashtable, (void*) presoldata->usefullogicor[c]) );
737  SCIP_CALL( SCIPreleaseCons(scip, &(presoldata->usefullogicor[c])) );
738 
739  presoldata->usefullogicor[c] = presoldata->usefullogicor[presoldata->nusefullogicor - 1];
740  --(presoldata->nusefullogicor);
741  }
742  }
743 
744  presoldata->firstchangedlogicor = presoldata->nusefullogicor;
745  assert(presoldata->firstchangedlogicor >= 0);
746 
747  /* add new logicor constraints */
748  for( c = nlogicors - 1; c >= 0; --c )
749  {
750  assert(SCIPconsIsActive(logicors[c]));
751 
752  if( !SCIPconsIsModifiable(logicors[c]) && SCIPgetNVarsLogicor(scip, logicors[c]) >= 3 )
753  {
754  /* check if constraint is new, and correct array size if necessary */
755  if( !SCIPhashtableExists(presoldata->logicorhashtable, (void*) logicors[c]) )
756  {
757  /* resize array if necessary */
758  if( presoldata->nusefullogicor == presoldata->susefullogicor )
759  {
760  int newsize;
761 
762  newsize = SCIPcalcMemGrowSize(scip, presoldata->nusefullogicor + 1);
763 
764  /* array already at maximal size */
765  if( newsize <= presoldata->susefullogicor )
766  return SCIP_NOMEMORY;
767 
768  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(presoldata->usefullogicor), presoldata->susefullogicor, newsize) );
769  presoldata->susefullogicor = newsize;
770  }
771 
772  /* insert new element in hashtable */
773  SCIP_CALL( SCIPhashtableInsert(presoldata->logicorhashtable, (void*) logicors[c]) );
774  SCIP_CALL( SCIPcaptureCons(scip, logicors[c]) );
775 
776  presoldata->usefullogicor[presoldata->nusefullogicor] = logicors[c];
777  ++(presoldata->nusefullogicor);
778 
779  /* update maximal entries in a logicor constraint */
780  if( presoldata->maxnvarslogicor < SCIPgetNVarsLogicor(scip, logicors[c]) )
781  presoldata->maxnvarslogicor = SCIPgetNVarsLogicor(scip, logicors[c]);
782  }
783  }
784  }
785 
786  return SCIP_OKAY;
787 }
788 
789 
790 /** extract and-constraints and set-partitioning constraints */
791 static
793  SCIP* scip, /**< SCIP data structure */
794  SCIP_PRESOLDATA* presoldata, /**< data object of presolver */
795  int pos, /**< position of logicor in usefullogicor array to presolve */
796  SCIP_HASHMAP* varmap, /**< variable map mapping inactive variables to their active representation */
797  SCIP_CONS** gateconss, /**< allocated memory for all gate-constraints */
798  SCIP_VAR** activevars, /**< allocated memory for active variables */
799  SCIP_VAR** posresultants, /**< allocated memory for all possible resultant variables */
800  HASHDATA* hashdata, /**< allocated memory for a hashdata object */
801  int* ndelconss, /**< pointer to store number of deleted constraints */
802  int* naddconss /**< pointer to store number of added constraints */
803  )
804 {
805  SCIP_VAR** logicorvars;
806  SCIP_VAR* tmpvars[2];
807  HASHDATA* hashmaphashdata;
808  SCIP_CONS* logicor;
809  SCIP_Bool negated;
810  int ngateconss;
811  int nlogicorvars;
812  int nposresultants;
813  int d;
814  int v;
815 
816  assert(scip != NULL);
817  assert(presoldata != NULL);
818  assert(0 <= pos && pos < presoldata->nusefullogicor);
819  assert(gateconss != NULL);
820  assert(activevars != NULL);
821  assert(posresultants != NULL);
822  assert(hashdata != NULL);
823  assert(hashdata->nvars == 2);
824  assert(hashdata->cons == NULL);
825  assert(ndelconss != NULL);
826  assert(naddconss != NULL);
827 
828  assert(presoldata->usefullogicor != NULL);
829  logicor = presoldata->usefullogicor[pos];
830  assert(logicor != NULL);
831 
832  if( !SCIPconsIsActive(logicor) )
833  return SCIP_OKAY;
834 
835  assert(!SCIPconsIsModifiable(logicor));
836 
837  nlogicorvars = SCIPgetNVarsLogicor(scip, logicor);
838  assert(nlogicorvars >= 3 && nlogicorvars <= presoldata->maxnvarslogicor);
839 
840  logicorvars = SCIPgetVarsLogicor(scip, logicor);
841  assert(logicorvars != NULL);
842 
843  nposresultants = 0;
844 
845  /* get active logicor variables and determine all possible resultants */
846  for( d = nlogicorvars - 1; d >= 0; --d )
847  {
848  /* do not work with fixed variables */
849  if( SCIPvarGetLbLocal(logicorvars[d]) > 0.5 || SCIPvarGetUbLocal(logicorvars[d]) < 0.5 )
850  return SCIP_OKAY;
851 
852  activevars[d] = (SCIP_VAR*) SCIPhashmapGetImage(varmap, logicorvars[d]);
853 
854  if( activevars[d] == NULL )
855  {
856  SCIP_CALL( SCIPgetBinvarRepresentative(scip, logicorvars[d], &(activevars[d]), &negated) );
857  SCIP_CALL( SCIPhashmapInsert(varmap, logicorvars[d], activevars[d]) );
858  }
859 
860  /* determine possible resultants a check if the other variables can appear in a set-packing constraint */
861  if( SCIPvarIsNegated(activevars[d]) )
862  {
863  assert(SCIPvarIsActive(SCIPvarGetNegatedVar(activevars[d])));
864 
865  if( SCIPvarGetNLocksDown(SCIPvarGetNegatedVar(activevars[d])) >= nlogicorvars - 1 )
866  {
867  posresultants[nposresultants] = activevars[d];
868  ++nposresultants;
869  }
870  else if( SCIPvarGetNLocksDown(SCIPvarGetNegatedVar(activevars[d])) == 0 )
871  return SCIP_OKAY;
872  }
873  else
874  {
875  assert(SCIPvarIsActive(activevars[d]));
876 
877  if( SCIPvarGetNLocksUp(activevars[d]) >= nlogicorvars - 1 )
878  {
879  posresultants[nposresultants] = activevars[d];
880  ++nposresultants;
881  }
882  else if( SCIPvarGetNLocksUp(activevars[d]) == 0 )
883  return SCIP_OKAY;
884  }
885  }
886 
887  if( nposresultants == 0 )
888  return SCIP_OKAY;
889 
890  /* sort variables after indices */
891  SCIPsortPtr((void**)activevars, SCIPvarComp, nlogicorvars);
892 
893  /* check that we have really different variables, if not remove the constraint from the hashmap and the data
894  * storage
895  */
896  for( d = nlogicorvars - 1; d > 0; --d )
897  {
898  if( SCIPvarGetIndex(activevars[d]) == SCIPvarGetIndex(activevars[d - 1]) )
899  {
900  assert(presoldata->usefullogicor[pos] == logicor);
901 
902  SCIP_CALL( SCIPhashtableRemove(presoldata->logicorhashtable, (void*) logicor) );
903  SCIP_CALL( SCIPreleaseCons(scip, &logicor) );
904 
905  presoldata->usefullogicor[pos] = presoldata->usefullogicor[presoldata->nusefullogicor - 1];
906  --(presoldata->nusefullogicor);
907 
908  return SCIP_OKAY;
909  }
910  }
911 
912  ngateconss = 0;
913 
914  for( d = nposresultants - 1; d >= 0; --d )
915  {
916  ngateconss = 0;
917 
918  for( v = nlogicorvars - 1; v >= 0; --v )
919  {
920  if( activevars[v] == posresultants[d] )
921  continue;
922 
923  /* variables need to be sorted */
924  if( SCIPvarCompare(posresultants[d], activevars[v]) > 0 )
925  {
926  tmpvars[0] = activevars[v];
927  tmpvars[1] = posresultants[d];
928  }
929  else
930  {
931  tmpvars[0] = posresultants[d];
932  tmpvars[1] = activevars[v];
933  }
934  hashdata->vars = tmpvars;
935 
936  hashmaphashdata = (HASHDATA*) SCIPhashtableRetrieve(presoldata->hashdatatable, (void*) hashdata);
937 
938  if( hashmaphashdata != NULL && SCIPconsIsActive(hashmaphashdata->cons) )
939  {
940  gateconss[ngateconss] = hashmaphashdata->cons;
941  ++ngateconss;
942  }
943  else
944  break;
945  }
946  if( ngateconss == nlogicorvars - 1 )
947  break;
948  }
949 
950  /* @todo, check for clique of all variables except the resultant */
951  /* check if we have a set-partitioning 'gate' */
952  if( ngateconss == nlogicorvars - 1 && nlogicorvars == 3 )
953  {
954  assert(d >= 0 && d < nposresultants);
955  assert(ngateconss >= 2);
956 
957  if( activevars[0] == posresultants[d] )
958  {
959  tmpvars[0] = activevars[1];
960  tmpvars[1] = activevars[2];
961  }
962  else if( activevars[1] == posresultants[d] )
963  {
964  tmpvars[0] = activevars[0];
965  tmpvars[1] = activevars[2];
966  }
967  else
968  {
969  assert(activevars[2] == posresultants[d]);
970  tmpvars[0] = activevars[0];
971  tmpvars[1] = activevars[1];
972  }
973  hashdata->vars = tmpvars;
974 
975  hashmaphashdata = (HASHDATA*) SCIPhashtableRetrieve(presoldata->hashdatatable, (void*) hashdata);
976  assert(hashmaphashdata == NULL || hashmaphashdata->cons != NULL);
977 
978  if( hashmaphashdata != NULL && SCIPconsIsActive(hashmaphashdata->cons) )
979  {
980  gateconss[ngateconss] = hashmaphashdata->cons;
981  ++ngateconss;
982  }
983  }
984 
985  /* did we find enough (>= number of variables in logicor - 1) set-packing constraints for an upgrade to either
986  * an and-constraint or even a set-partitioning constraint
987  */
988  if( ngateconss == nlogicorvars || (ngateconss >= nlogicorvars - 1 && !presoldata->onlysetpart))
989  {
990  SCIP_CONS* newcons;
991  char name[SCIP_MAXSTRLEN];
992  SCIP_Bool initial;
993  SCIP_Bool separate;
994  SCIP_Bool enforce;
995  SCIP_Bool check;
996  SCIP_Bool propagate;
997  SCIP_Bool local;
998  SCIP_Bool modifiable;
999  SCIP_Bool dynamic;
1000  SCIP_Bool removable;
1001  SCIP_Bool stickingatnode;
1002  int i;
1003 
1004  assert(ngateconss <= nlogicorvars);
1005  assert(d >= 0 && d < nposresultants);
1006 
1007  initial = SCIPconsIsInitial(logicor);
1008  separate = SCIPconsIsSeparated(logicor);
1009  enforce = SCIPconsIsEnforced(logicor);
1010  check = SCIPconsIsChecked(logicor);
1011  propagate = SCIPconsIsPropagated(logicor);
1012  local = SCIPconsIsLocal(logicor);
1013  modifiable = SCIPconsIsModifiable(logicor);
1014  dynamic = SCIPconsIsDynamic(logicor);
1015  removable = SCIPconsIsRemovable(logicor);
1016  stickingatnode = SCIPconsIsStickingAtNode(logicor);
1017 
1018 #ifdef SCIP_DEBUG
1019  if( ngateconss == nlogicorvars )
1020  {
1021  SCIPdebugMessage("Following constraints form a set-partitioning constraint.\n");
1022  }
1023  else
1024  {
1025  SCIPdebugMessage("Following constraints form an and-constraint.\n");
1026  }
1027 #endif
1028 
1029  for( v = ngateconss - 1; v >= 0; --v )
1030  {
1031  assert(gateconss[v] != NULL);
1032 
1033  initial |= SCIPconsIsInitial(gateconss[v]);
1034  separate |= SCIPconsIsSeparated(gateconss[v]);
1035  enforce |= SCIPconsIsEnforced(gateconss[v]);
1036  check |= SCIPconsIsChecked(gateconss[v]);
1037  propagate |= SCIPconsIsPropagated(gateconss[v]);
1038  local &= SCIPconsIsLocal(gateconss[v]);
1039  modifiable &= SCIPconsIsModifiable(gateconss[v]);
1040  dynamic &= SCIPconsIsDynamic(gateconss[v]);
1041  removable &= SCIPconsIsRemovable(gateconss[v]);
1042  stickingatnode &= SCIPconsIsStickingAtNode(gateconss[v]);
1043 
1044  SCIPdebugPrintCons(scip, gateconss[v], NULL);
1045 
1046  SCIP_CALL( SCIPdelCons(scip, gateconss[v]) );
1047  ++(*ndelconss);
1048  }
1049 
1050  SCIPdebugPrintCons(scip, logicor, NULL);
1051 
1052  if( ngateconss == nlogicorvars - 1 )
1053  {
1054  SCIP_VAR** consvars;
1055 
1056  assert(!presoldata->onlysetpart);
1057 
1058  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, ngateconss) );
1059  i = 0;
1060 
1061  /* determine and operands */
1062  for( v = nlogicorvars - 1; v >= 0; --v )
1063  {
1064  if( activevars[v] == posresultants[d] )
1065  continue;
1066 
1067  SCIP_CALL( SCIPgetNegatedVar(scip, activevars[v], &consvars[i]) );
1068  ++i;
1069  }
1070  assert(i == ngateconss);
1071 
1072  /* create and add "and" constraint for the extracted gate */
1073  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "andgate_%d", presoldata->ngates);
1074  SCIP_CALL( SCIPcreateConsAnd(scip, &newcons, name, posresultants[d], ngateconss, consvars,
1075  initial, separate, enforce, check, propagate,
1076  local, modifiable, dynamic, removable, stickingatnode) );
1077 
1078  SCIP_CALL( SCIPaddCons(scip, newcons) );
1079  SCIPdebugMessage("-------------->\n");
1080  SCIPdebugPrintCons(scip, newcons, NULL);
1081 
1082  ++(*naddconss);
1083  ++(presoldata->ngates);
1084 
1085  SCIP_CALL( SCIPdelCons(scip, logicor) );
1086  ++(*ndelconss);
1087 
1088  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1089 
1090  SCIPfreeBufferArray(scip, &consvars);
1091  }
1092  else
1093  {
1094  assert(ngateconss == nlogicorvars);
1095 
1096  /* create and add set-partitioning constraint */
1097  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "setpart_%d", presoldata->ngates);
1098  SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, name, nlogicorvars, activevars,
1099  initial, separate, enforce, check, propagate,
1100  local, modifiable, dynamic, removable, stickingatnode) );
1101 
1102  SCIP_CALL( SCIPaddCons(scip, newcons) );
1103  SCIPdebugMessage("-------------->\n");
1104  SCIPdebugPrintCons(scip, newcons, NULL);
1105 
1106  ++(*naddconss);
1107  ++(presoldata->ngates);
1108 
1109  SCIP_CALL( SCIPdelCons(scip, logicor) );
1110  ++(*ndelconss);
1111 
1112  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1113  }
1114  }
1115 
1116  return SCIP_OKAY;
1117 }
1118 
1119 
1120 /*
1121  * Callback methods of presolver
1122  */
1123 
1124 
1125 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
1126 static
1127 SCIP_DECL_PRESOLCOPY(presolCopyGateextraction)
1128 { /*lint --e{715}*/
1129  assert(scip != NULL);
1130  assert(presol != NULL);
1131  assert(strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0);
1132 
1133  /* call inclusion method of presolver */
1135 
1136  return SCIP_OKAY;
1137 }
1138 
1139 
1140 /** destructor of presolver to free user data (called when SCIP is exiting) */
1141 static
1142 SCIP_DECL_PRESOLFREE(presolFreeGateextraction)
1143 { /*lint --e{715}*/
1144  SCIP_PRESOLDATA* presoldata;
1145 
1146  /* free presolver data */
1147  presoldata = SCIPpresolGetData(presol);
1148  assert(presoldata != NULL);
1149 
1150  if( presoldata->hashdatatable != NULL )
1151  {
1152  assert(presoldata->setppchashtable != NULL);
1153  assert(presoldata->logicorhashtable != NULL);
1154 
1155  SCIPhashtableFree(&(presoldata->logicorhashtable));
1156  SCIPhashtableFree(&(presoldata->setppchashtable));
1157  SCIPhashtableFree(&(presoldata->hashdatatable));
1158  }
1159 
1160  SCIPfreeMemory(scip, &presoldata);
1161  SCIPpresolSetData(presol, NULL);
1162 
1163  return SCIP_OKAY;
1164 }
1165 
1166 
1167 /** deinitialization method of presolver (called before transformed problem is freed) */
1168 static
1169 SCIP_DECL_PRESOLEXIT(presolExitGateextraction)
1170 { /*lint --e{715}*/
1171  SCIP_PRESOLDATA* presoldata;
1172  int c;
1173 
1174  /* free presolver data */
1175  presoldata = SCIPpresolGetData(presol);
1176  assert(presoldata != NULL);
1177 
1178  /* release old constraints */
1179  for( c = presoldata->nusefullogicor - 1; c >= 0; --c )
1180  {
1181  SCIP_CALL( SCIPreleaseCons(scip, &(presoldata->usefullogicor[c])) );
1182  }
1183 
1184  if( presoldata->usefullogicorexist )
1185  {
1186  SCIPfreeBlockMemoryArray(scip, &presoldata->usefullogicor, presoldata->susefullogicor);
1187  }
1188 
1189  if( presoldata->usefulsetppcexist )
1190  {
1191  assert(presoldata->setppchashdatas != NULL || presoldata->nsetppchashdatas == 0);
1192  for( c = presoldata->nsetppchashdatas - 1; c >= 0; --c )
1193  {
1194  assert(presoldata->setppchashdatas[c] != NULL);
1195  assert(presoldata->setppchashdatas[c]->cons != NULL);
1196  assert(presoldata->setppchashdatas[c]->vars != NULL);
1197 
1198  /* remove constraint from setppc-hashtable */
1199  assert(SCIPhashtableExists(presoldata->setppchashtable, (void*) presoldata->setppchashdatas[c]->cons));
1200  SCIP_CALL( SCIPhashtableRemove(presoldata->setppchashtable, (void*) presoldata->setppchashdatas[c]->cons) );
1201 
1202  /* release old constraints */
1203  SCIP_CALL( SCIPreleaseCons(scip, &(presoldata->setppchashdatas[c]->cons)) );
1204 
1205  /* remove hashdata entry from hashtable */
1206  SCIP_CALL( SCIPhashtableRemove(presoldata->hashdatatable, (void*) presoldata->setppchashdatas[c]) );
1207 
1208  /* release variables */
1209  SCIP_CALL( SCIPreleaseVar(scip, &(presoldata->setppchashdatas[c]->vars[0])) );
1210  SCIP_CALL( SCIPreleaseVar(scip, &(presoldata->setppchashdatas[c]->vars[1])) );
1211 
1212  /* free memory for variables */
1213  SCIPfreeBlockMemoryArray(scip, &(presoldata->setppchashdatas[c]->vars), 2);
1214  }
1215 
1216  SCIPfreeBlockMemoryArray(scip, &(presoldata->setppchashdatastore), presoldata->ssetppchashdatas);
1217  SCIPfreeBlockMemoryArray(scip, &(presoldata->setppchashdatas), presoldata->ssetppchashdatas);
1218  }
1219 
1220  if( presoldata->hashdatatable != NULL )
1221  {
1222  assert(presoldata->setppchashtable != NULL);
1223  assert(presoldata->logicorhashtable != NULL);
1224 
1225  /* clear old hashtable entries */
1226  SCIPhashtableRemoveAll(presoldata->hashdatatable);
1227  SCIPhashtableRemoveAll(presoldata->setppchashtable);
1228  SCIPhashtableRemoveAll(presoldata->logicorhashtable);
1229  }
1230 
1231  presoldata->nusefullogicor = 0;
1232  presoldata->susefullogicor = 0;
1233  presoldata->nsetppchashdatas = 0;
1234  presoldata->ssetppchashdatas = 0;
1235  presoldata->firstchangedlogicor = -1;
1236  presoldata->ngates = 0;
1237  presoldata->usefullogicorexist = FALSE;
1238  presoldata->usefulsetppcexist = FALSE;
1239  presoldata->newsetppchashdatas = FALSE;
1240  presoldata->initialized = FALSE;
1241 
1242  return SCIP_OKAY;
1243 }
1244 
1245 
1246 /** presolving initialization method of presolver (called when presolving is about to begin) */
1247 static
1248 SCIP_DECL_PRESOLINITPRE(presolInitpreGateextraction)
1249 { /*lint --e{715}*/
1250  return SCIP_OKAY;
1251 }
1252 
1253 
1254 /** presolving deinitialization method of presolver (called after presolving has been finished) */
1255 static
1256 SCIP_DECL_PRESOLEXITPRE(presolExitpreGateextraction)
1257 { /*lint --e{715}*/
1258  return SCIP_OKAY;
1259 }
1260 
1261 
1262 #define HASHTABLESIZE_FACTOR 5
1263 
1264 /** execution method of presolver */
1265 static
1266 SCIP_DECL_PRESOLEXEC(presolExecGateextraction)
1267 { /*lint --e{715}*/
1268  SCIP_PRESOLDATA* presoldata;
1269  SCIP_HASHMAP* varmap;
1270  HASHDATA* hashdata;
1271  SCIP_CONSHDLR* conshdlrsetppc;
1272  SCIP_CONSHDLR* conshdlrlogicor;
1273  SCIP_CONSHDLR* conshdlrand;
1274  SCIP_CONS** setppcconss;
1275  SCIP_CONS** logicorconss;
1276  int nsetppcconss;
1277  int nlogicorconss;
1278  int size;
1279  int c;
1280  SCIP_Bool paramvalue;
1281 
1282  assert(scip != NULL);
1283  assert(presol != NULL);
1284  assert(strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0);
1285  assert(result != NULL);
1286 
1287  *result = SCIP_DIDNOTRUN;
1288 
1289 #if 0 /* need to include cons_knapsack on top of this file */
1290  /* check for possible knapsacks that form with a logicor a weak relaxation of an and-constraint
1291  *
1292  * the weak relaxation of an and-constraint looks like:
1293  * - row1: resvar - v1 - ... - vn >= 1-n
1294  * - row2: n*resvar - v1 - ... - vn <= 0.0
1295  *
1296  * which look like the following contraints
1297  * - logicor: resvar + ~v1 + ... + ~vn >= 1
1298  * - knapsack: n*resvar + ~v1 + ... + ~vn <= n
1299  */
1300  {
1301  SCIP_CONSHDLR* conshdlrknapsack;
1302  SCIP_CONS** knapsackconss;
1303  int nknapsackconss;
1304  SCIP_VAR** vars;
1305  SCIP_Longint* vals;
1306  SCIP_Longint capacity;
1307  int nvars;
1308 
1309  conshdlrknapsack = SCIPfindConshdlr(scip, "knapsack");
1310 
1311  /* get number of active constraints */
1312  knapsackconss = SCIPconshdlrGetConss(conshdlrknapsack);
1313  nknapsackconss = SCIPconshdlrGetNActiveConss(conshdlrknapsack);
1314  assert(nknapsackconss >= 0);
1315  assert(knapsackconss != NULL || nknapsackconss == 0);
1316 
1317  for( c = nknapsackconss - 1; c >= 0; --c )
1318  {
1319  /* not implemented in master branch, but the constraint may be already sorted */
1320  /*SCIPsortKnapsack(scip, knapsackconss[c]);*/
1321 
1322  nvars = SCIPgetNVarsKnapsack(scip, knapsackconss[c]);
1323  vals = SCIPgetWeightsKnapsack(scip, knapsackconss[c]);
1324  vars = SCIPgetVarsKnapsack(scip, knapsackconss[c]);
1325  capacity = SCIPgetCapacityKnapsack(scip, knapsackconss[c]);
1326 
1327  if( nvars > 1 && capacity == nvars - 1 && vals[0] == capacity && vals[1] == 1 )
1328  {
1329  printf("possible knapsack for gate extraction\n");
1330  }
1331  }
1332  }
1333 #endif
1334 
1335  /* get necessary constraint handlers */
1336  conshdlrsetppc = SCIPfindConshdlr(scip, "setppc");
1337  conshdlrlogicor = SCIPfindConshdlr(scip, "logicor");
1338 
1339  if( conshdlrsetppc == NULL || conshdlrlogicor == NULL )
1340  return SCIP_OKAY;
1341 
1342  /* get number of active constraints */
1343  nsetppcconss = SCIPconshdlrGetNActiveConss(conshdlrsetppc);
1344  assert(nsetppcconss >= 0);
1345  nlogicorconss = SCIPconshdlrGetNActiveConss(conshdlrlogicor);
1346  assert(nlogicorconss >= 0);
1347 
1348  if( nsetppcconss == 0 || nlogicorconss == 0 )
1349  return SCIP_OKAY;
1350 
1351  /* get presolver data */
1352  presoldata = SCIPpresolGetData(presol);
1353  assert(presoldata != NULL);
1354 
1355  conshdlrand = SCIPfindConshdlr(scip, "and");
1356 
1357  /* need and-constraint handler to extract and-gates */
1358  if( conshdlrand == NULL )
1359  {
1360  /* nothing to do when we cannot extract anything */
1361  if( !presoldata->searchequations )
1362  return SCIP_OKAY;
1363  else
1364  {
1365  /* make sure that we correct the parameter for only extrating set-partitioning constraints */
1366  if( SCIPisParamFixed(scip, "presolving/"PRESOL_NAME"/onlysetpart") )
1367  {
1368  SCIPwarningMessage(scip, "unfixing parameter <presolving/"PRESOL_NAME"/onlysetpart> in gate extration presolver\n");
1369  SCIP_CALL( SCIPunfixParam(scip, "presolving/"PRESOL_NAME"/onlysetpart") );
1370  }
1371  SCIP_CALL( SCIPsetBoolParam(scip, "presolving/"PRESOL_NAME"/onlysetpart", TRUE) );
1372  assert(presoldata->onlysetpart);
1373  }
1374  }
1375 
1376  paramvalue = FALSE;
1377  if( conshdlrand != NULL && SCIPgetBoolParam(scip, "constraints/and/linearize", &paramvalue) == SCIP_OKAY )
1378  {
1379  if( paramvalue )
1380  {
1381  SCIPwarningMessage(scip, "Gate-presolving is the 'counterpart' of linearizing all and-constraints, so enabling both presolving steps at ones does not make sense.\n");
1382  }
1383  }
1384  *result = SCIP_DIDNOTFIND;
1385 
1386  /* get active constraints */
1387  SCIP_CALL( SCIPduplicateBufferArray(scip, &setppcconss, SCIPconshdlrGetConss(conshdlrsetppc), nsetppcconss) );
1388 
1389  assert(setppcconss != NULL);
1390  logicorconss = SCIPconshdlrGetConss(conshdlrlogicor);
1391  assert(logicorconss != NULL);
1392 
1393  /* first we need to initialized the hashtables if not yet done */
1394  if( presoldata->hashdatatable == NULL )
1395  {
1396  SCIP_CALL( presoldataInitHashtables(scip, presoldata) );
1397  }
1398  assert(presoldata->hashdatatable != NULL);
1399  assert(presoldata->setppchashtable != NULL);
1400  assert(presoldata->logicorhashtable != NULL);
1401 
1402  presoldata->newsetppchashdatas = FALSE;
1403 
1404  if( !presoldata->initialized )
1405  {
1406  assert(presoldata->usefullogicor == NULL);
1407 
1408  /* create useful set-packing information by adding new set-packing constraints with two variables */
1409  SCIP_CALL( createPresoldata(scip, presoldata, setppcconss, nsetppcconss, logicorconss, nlogicorconss) );
1410  }
1411  else
1412  {
1413  /* refresh useful set-packing information, delete redundant constraints and add new constraints */
1414  SCIP_CALL( correctPresoldata(scip, presoldata, setppcconss, nsetppcconss, logicorconss, nlogicorconss) );
1415  }
1416  assert(presoldata->initialized);
1417 
1418  if( presoldata->nusefullogicor == 0 )
1419  goto TERMINATE;
1420 
1421  /* move the biggate extraction to front or back by sort the logicors after number of variables */
1422 
1423  if( presoldata->sorting != 0 )
1424  {
1425  int* lengths;
1426 
1427  SCIP_CALL( SCIPallocBufferArray(scip, &lengths, presoldata->nusefullogicor) );
1428 
1429  for( c = presoldata->nusefullogicor - 1; c >= 0; --c )
1430  {
1431  lengths[c] = SCIPgetNVarsLogicor(scip, presoldata->usefullogicor[c]);
1432  }
1433 
1434  if( presoldata->sorting == -1 )
1435  SCIPsortDownIntPtr(lengths, (void**)presoldata->usefullogicor, presoldata->nusefullogicor);
1436  else
1437  SCIPsortIntPtr(lengths, (void**)presoldata->usefullogicor, presoldata->nusefullogicor);
1438 
1439  SCIPfreeBufferArray(scip, &lengths);
1440  }
1441 
1442  /* maximal number of binary variables */
1443  size = SCIPgetNBinVars(scip) + SCIPgetNImplVars(scip);
1444 
1445  /* create the variable mapping hash map */
1447 
1448  /* search for set-partitioning constraints arising from a logicor and a set-packing constraints with equal variables */
1449  if( presoldata->searchequations && !SCIPisStopped(scip) )
1450  {
1451  SCIP_HASHTABLE* setppchashdatatable;
1452  HASHDATA** setppchashdatas;
1453  HASHDATA* setppchashdatastore;
1454  HASHDATA* hashmaphashdata;
1455  SCIP_CONS* logicor;
1456  SCIP_CONS* setppc;
1457  SCIP_VAR** logicorvars;
1458  SCIP_VAR** setppcvars;
1459  SCIP_VAR** activevarslogicor;
1460  SCIP_VAR** activevarssetppc;
1461  SCIP_Bool negated;
1462  int nsetppchashdatas;
1463  int nlogicorvars;
1464  int nsetppcvars;
1465  int d;
1466  int v;
1467 
1468  assert(nsetppcconss > 0);
1469 
1470  /* create local hashtable */
1471  SCIP_CALL( SCIPhashtableCreate(&setppchashdatatable, SCIPblkmem(scip), 5 * nsetppcconss, SCIPhashGetKeyStandard, setppcHashdataKeyEqCons, setppcHashdataKeyValCons, (void*) scip) );
1472 
1473  /* maximal number of binary variables */
1474  size = presoldata->maxnvarslogicor;
1475  assert(size >= 3);
1476 
1477  /* get temporary memory */
1478  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &setppchashdatastore, nsetppcconss) );
1479  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &setppchashdatas, nsetppcconss) );
1480  SCIP_CALL( SCIPallocBufferArray(scip, &activevarssetppc, size) );
1481  SCIP_CALL( SCIPallocBufferArray(scip, &activevarslogicor, size) );
1482 
1483  /* allocate memory for the temporary hashdata object to search for a corresponding set-packing/-partitioning
1484  * constraint
1485  */
1486  SCIP_CALL( SCIPallocBuffer(scip, &hashdata) );
1487  hashdata->cons = NULL;
1488 
1489  nsetppchashdatas = 0;
1490 
1491  /* collect all set-packing/-partitioning constraints and corresponding data to be able to search faster */
1492  for( d = nsetppcconss - 1; d >= 0; --d )
1493  {
1494  setppc = setppcconss[d];
1495  assert(setppc != NULL);
1496 
1497  if( SCIPconsIsDeleted(setppc) )
1498  continue;
1499 
1500  /* @todo if of interest could also be implemented for set-covering constraints */
1501 #if 1
1502  if( SCIPgetTypeSetppc(scip, setppc) == SCIP_SETPPCTYPE_COVERING )
1503  continue;
1504 #endif
1505 
1506  nsetppcvars = SCIPgetNVarsSetppc(scip, setppc);
1507 
1508  if( nsetppcvars < 2 )
1509  continue;
1510 
1511  if( SCIPconsIsModifiable(setppc) )
1512  continue;
1513 
1514  /* to big setppc constraints are picked out */
1515  if( nsetppcvars > size )
1516  continue;
1517 
1518  setppcvars = SCIPgetVarsSetppc(scip, setppc);
1519  assert(setppcvars != NULL);
1520 
1521  /* get active setppc variables */
1522  for( v = nsetppcvars - 1; v >= 0; --v )
1523  {
1524  /* do not work with fixed variables */
1525  if( SCIPvarGetLbLocal(setppcvars[v]) > 0.5 || SCIPvarGetUbLocal(setppcvars[v]) < 0.5 )
1526  break;
1527 
1528  activevarssetppc[v] = (SCIP_VAR*) SCIPhashmapGetImage(varmap, setppcvars[v]);
1529 
1530  if( activevarssetppc[v] == NULL )
1531  {
1532  SCIP_CALL( SCIPgetBinvarRepresentative(scip, setppcvars[v], &(activevarssetppc[v]), &negated) );
1533  SCIP_CALL( SCIPhashmapInsert(varmap, setppcvars[v], activevarssetppc[v]) );
1534  }
1535  }
1536 
1537  /* if we found a fixed variable we want disregard this constraint */
1538  if( v >= 0 )
1539  continue;
1540 
1541  /* variables need to be sorted after indices to be able to do a fast comparison */
1542  SCIPsortPtr((void**)activevarssetppc, SCIPvarComp, nsetppcvars);
1543 
1544  setppchashdatas[nsetppchashdatas] = &(setppchashdatastore[nsetppchashdatas]);
1545 
1546  /* memorize set-packing data */
1547  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(setppchashdatas[nsetppchashdatas]->vars), activevarssetppc, nsetppcvars) );
1548 
1549  setppchashdatas[nsetppchashdatas]->nvars = nsetppcvars;
1550  setppchashdatas[nsetppchashdatas]->cons = setppc;
1551  /* need to capture this constraint, because it might get deleted during the process */
1552  SCIP_CALL( SCIPcaptureCons(scip, setppc) );
1553 
1554  /* add entry to local hashtable */
1555  SCIP_CALL( SCIPhashtableInsert(setppchashdatatable, (void*) setppchashdatas[nsetppchashdatas]) );
1556  ++nsetppchashdatas;
1557  }
1558 
1559  /* check all (new) logicors against all collected set-packing/-partitioning constraints */
1560  for( c = nlogicorconss - 1; c >= 0 && !SCIPisStopped(scip); --c )
1561  {
1562  logicor = logicorconss[c];
1563  assert(logicor != NULL);
1564 
1565  if( SCIPconsIsDeleted(logicor) )
1566  continue;
1567 
1568  nlogicorvars = SCIPgetNVarsLogicor(scip, logicor);
1569 
1570  if( nlogicorvars < 2 )
1571  continue;
1572 
1573  if( SCIPconsIsModifiable(logicor) )
1574  continue;
1575 
1576  assert(nlogicorvars <= size);
1577 
1578  logicorvars = SCIPgetVarsLogicor(scip, logicor);
1579  assert(logicorvars != NULL);
1580 
1581  /* get active logicor variables */
1582  for( v = nlogicorvars - 1; v >= 0; --v )
1583  {
1584  /* do not work with fixed variables */
1585  if( SCIPvarGetLbLocal(logicorvars[v]) > 0.5 || SCIPvarGetUbLocal(logicorvars[v]) < 0.5 )
1586  break;
1587 
1588  activevarslogicor[v] = (SCIP_VAR*) SCIPhashmapGetImage(varmap, logicorvars[v]);
1589 
1590  /* if image does not exist, then there is no corresponding set-packing constraint */
1591  if( activevarslogicor[v] == NULL )
1592  break;
1593  }
1594 
1595  if( v == -1 )
1596  {
1597  /* need sorting to be able to find the correct hashdata element */
1598  SCIPsortPtr((void**)activevarslogicor, SCIPvarComp, nlogicorvars);
1599 
1600  hashdata->nvars = nlogicorvars;
1601  hashdata->vars = activevarslogicor;
1602 
1603  hashmaphashdata = (HASHDATA*) SCIPhashtableRetrieve(setppchashdatatable, (void*) hashdata);
1604  assert(hashmaphashdata == NULL || hashmaphashdata->cons != NULL);
1605 
1606  if( hashmaphashdata != NULL && !SCIPconsIsDeleted(hashmaphashdata->cons) )
1607  {
1608  SCIP_Bool initial;
1609  SCIP_Bool separate;
1610  SCIP_Bool enforce;
1611  SCIP_Bool check;
1612  SCIP_Bool propagate;
1613  SCIP_Bool local;
1614  SCIP_Bool modifiable;
1615  SCIP_Bool dynamic;
1616  SCIP_Bool removable;
1617  SCIP_Bool stickingatnode;
1618 
1619  setppc = hashmaphashdata->cons;
1620  assert(SCIPconsGetHdlr(setppc) == SCIPfindConshdlr(scip, "setppc"));
1621 
1622  initial = SCIPconsIsInitial(logicor) || SCIPconsIsInitial(setppc);
1623  separate = SCIPconsIsSeparated(logicor) || SCIPconsIsSeparated(setppc);
1624  enforce = SCIPconsIsEnforced(logicor) || SCIPconsIsEnforced(setppc);
1625  check = SCIPconsIsChecked(logicor) || SCIPconsIsChecked(setppc);
1626  propagate = SCIPconsIsPropagated(logicor) || SCIPconsIsPropagated(setppc);
1627  local = SCIPconsIsLocal(logicor) && SCIPconsIsLocal(setppc);
1628  modifiable = SCIPconsIsModifiable(logicor) && SCIPconsIsModifiable(setppc);
1629  dynamic = SCIPconsIsDynamic(logicor) && SCIPconsIsDynamic(setppc);
1630  removable = SCIPconsIsRemovable(logicor) && SCIPconsIsRemovable(setppc);
1631  stickingatnode = SCIPconsIsStickingAtNode(logicor) && SCIPconsIsStickingAtNode(setppc);
1632 
1633  /* check if logicor is redundant against a set-partitioning constraint */
1634  if( SCIPgetTypeSetppc(scip, setppc) == SCIP_SETPPCTYPE_PARTITIONING )
1635  {
1636  SCIP_CALL( SCIPsetConsInitial(scip, setppc, initial) );
1637  SCIP_CALL( SCIPsetConsSeparated(scip, setppc, separate) );
1638  SCIP_CALL( SCIPsetConsEnforced(scip, setppc, enforce) );
1639  SCIP_CALL( SCIPsetConsChecked(scip, setppc, check) );
1640  SCIP_CALL( SCIPsetConsPropagated(scip, setppc, propagate) );
1641  SCIP_CALL( SCIPsetConsLocal(scip, setppc, local) );
1642  SCIP_CALL( SCIPsetConsModifiable(scip, setppc, modifiable) );
1643  SCIP_CALL( SCIPsetConsDynamic(scip, setppc, dynamic) );
1644  SCIP_CALL( SCIPsetConsRemovable(scip, setppc, removable) );
1645  SCIP_CALL( SCIPsetConsStickingAtNode(scip, setppc, stickingatnode) );
1646 
1647  SCIPdebugMessage("Following logicor is redundant to the set-partitioning constraint.\n");
1648  SCIPdebugPrintCons(scip, logicor, NULL);
1649  SCIPdebugPrintCons(scip, setppc, NULL);
1650  }
1651  else
1652  {
1653  SCIP_CONS* newcons;
1654  char name[SCIP_MAXSTRLEN];
1655 
1656  assert(SCIPgetTypeSetppc(scip, setppc) == SCIP_SETPPCTYPE_PACKING);
1657 
1658  SCIPdebugMessage("Following logicor and set-packing constraints form a set-partitioning constraint.\n");
1659  SCIPdebugPrintCons(scip, logicor, NULL);
1660  SCIPdebugPrintCons(scip, setppc, NULL);
1661 
1662  /* create and add set-partitioning constraint */
1663  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "setpart_%d", presoldata->ngates);
1664  SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, name, nlogicorvars, activevarslogicor,
1665  initial, separate, enforce, check, propagate,
1666  local, modifiable, dynamic, removable, stickingatnode) );
1667 
1668  SCIP_CALL( SCIPaddCons(scip, newcons) );
1669  SCIPdebugMessage("-------------->\n");
1670  SCIPdebugPrintCons(scip, newcons, NULL);
1671 
1672  ++(*naddconss);
1673  ++(presoldata->ngates);
1674 
1675  /* delete redundant set-packing constraint */
1676  SCIP_CALL( SCIPdelCons(scip, setppc) );
1677  ++(*ndelconss);
1678 
1679  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1680  }
1681 
1682  /* delete redundant logicor constraint */
1683  SCIP_CALL( SCIPdelCons(scip, logicor) );
1684  ++(*ndelconss);
1685  }
1686  }
1687  }
1688 
1689  /* need to clear/release parts of hashdata objects */
1690  for( d = nsetppchashdatas - 1; d >= 0; --d )
1691  {
1692  /* need to release captured constraint */
1693  SCIP_CALL( SCIPreleaseCons(scip, &(setppchashdatas[d]->cons)) );
1694  /* need to free copied memory */
1695  SCIPfreeBlockMemoryArray(scip, &(setppchashdatas[d]->vars), setppchashdatas[d]->nvars);
1696  }
1697 
1698  /* delete local hashtable */
1699  SCIPhashtableFree(&setppchashdatatable);
1700 
1701  /* free all temporary memory */
1702  SCIPfreeBuffer(scip, &hashdata);
1703  SCIPfreeBufferArray(scip, &activevarslogicor);
1704  SCIPfreeBufferArray(scip, &activevarssetppc);
1705  SCIPfreeBlockMemoryArray(scip, &setppchashdatas, nsetppcconss);
1706  SCIPfreeBlockMemoryArray(scip, &setppchashdatastore, nsetppcconss);
1707  }
1708 
1709  /* we do not have any useful set-packing or logicor constraint, or since last run did not get any new constraints, so abort */
1710  if( presoldata->nsetppchashdatas == 0 || (presoldata->firstchangedlogicor == presoldata->nusefullogicor && !presoldata->newsetppchashdatas) )
1711  {
1712  SCIPhashmapFree(&varmap);
1713  goto TERMINATE;
1714  }
1715 
1716  assert(presoldata->usefullogicor != NULL);
1717  assert(presoldata->nusefullogicor > 0);
1718  assert(presoldata->firstchangedlogicor >= 0);
1719  assert(presoldata->nsetppchashdatas > 0);
1720 
1721  /* search for gates */
1722  if( presoldata->nsetppchashdatas > 0 && !SCIPisStopped(scip) )
1723  {
1724  SCIP_CONS** gateconss;
1725  SCIP_VAR** activevars;
1726  SCIP_VAR** posresultants;
1727  int endloop;
1728 
1729  /* if we found new setppcs we want to check all logicors again */
1730  if( presoldata->newsetppchashdatas )
1731  endloop = 0;
1732  else
1733  endloop = MAX(presoldata->firstchangedlogicor, 0);
1734 
1735  assert(presoldata->maxnvarslogicor >= 3);
1736  SCIP_CALL( SCIPallocBufferArray(scip, &gateconss, presoldata->maxnvarslogicor) );
1737  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, presoldata->maxnvarslogicor) );
1738  SCIP_CALL( SCIPallocBufferArray(scip, &posresultants, presoldata->maxnvarslogicor) );
1739  SCIP_CALL( SCIPallocBuffer(scip, &hashdata) );
1740 
1741  hashdata->nvars = 2;
1742  hashdata->cons = NULL;
1743 
1744  /* check all (new) logicors against all set-packing constraints, to extract and-constraints with two or more
1745  * operands or set-partitioning constraints three or more variables
1746  */
1747  for( c = presoldata->nusefullogicor - 1; c >= endloop && !SCIPisStopped(scip); --c )
1748  {
1749  assert(presoldata->usefullogicor[c] != NULL);
1750 
1751  /* logicor constraint has the form: x + y + z >= 1
1752  *
1753  * find set-packing constraints: (~x + ~y >= 1 and ~x + ~z >= 1) <=> (x + y <= 1 and x + z <= 1)
1754  *
1755  * - these three constraints are aquivalent to: x = ~y * ~z (x = AND(~y,~z))
1756  *
1757  * if an additional set-packing constraint exists: y + z <= 1
1758  *
1759  * - these four constraints are aquivalent to: x + y + z = 1
1760  */
1761  SCIP_CALL( extractGates(scip, presoldata, c, varmap, gateconss, activevars, posresultants, hashdata, ndelconss, naddconss) );
1762  }
1763  SCIPfreeBuffer(scip, &hashdata);
1764  SCIPfreeBufferArray(scip, &posresultants);
1765  SCIPfreeBufferArray(scip, &activevars);
1766  SCIPfreeBufferArray(scip, &gateconss);
1767  }
1768 
1769  SCIPhashmapFree(&varmap);
1770 
1771  TERMINATE:
1772  SCIPfreeBufferArray(scip, &setppcconss);
1773 
1774  /* remove old setppchashdatas objects */
1775  SCIP_CALL( cleanupHashDatas(scip, presoldata) );
1776 
1777  return SCIP_OKAY;
1778 }
1779 
1780 
1781 /*
1782  * presolver specific interface methods
1783  */
1784 
1785 /** creates the gateextraction presolver and includes it in SCIP */
1787  SCIP* scip /**< SCIP data structure */
1788  )
1789 {
1790  SCIP_PRESOLDATA* presoldata;
1791  SCIP_PRESOL* presol;
1792 
1793  /* alloc presolve data object */
1794  SCIP_CALL( SCIPallocMemory(scip, &presoldata) );
1795 
1796  /* initialize gateextraction presolver data */
1797  presoldataInit(presoldata);
1798 
1799  /* include presolver */
1801  PRESOL_DELAY, presolExecGateextraction, presoldata) );
1802 
1803  SCIP_CALL( SCIPsetPresolCopy(scip, presol, presolCopyGateextraction) );
1804  SCIP_CALL( SCIPsetPresolFree(scip, presol, presolFreeGateextraction) );
1805  SCIP_CALL( SCIPsetPresolExit(scip, presol, presolExitGateextraction) );
1806  SCIP_CALL( SCIPsetPresolInitpre(scip, presol, presolInitpreGateextraction) );
1807  SCIP_CALL( SCIPsetPresolExitpre(scip, presol, presolExitpreGateextraction) );
1808 
1809  /* add gateextraction presolver parameters */
1811  "presolving/"PRESOL_NAME"/onlysetpart",
1812  "should we only try to extract set-partitioning constraints and no and-constraints",
1813  &presoldata->onlysetpart, TRUE, DEFAULT_ONLYSETPART, NULL, NULL) );
1814 
1815  /* add gateextraction presolver parameters */
1817  "presolving/"PRESOL_NAME"/searchequations",
1818  "should we try to extract set-partitioning constraint out of one logicor and one corresponding set-packing constraint",
1819  &presoldata->searchequations, TRUE, DEFAULT_SEARCHEQUATIONS, NULL, NULL) );
1820 
1821  /* add gateextraction presolver parameters */
1822  SCIP_CALL( SCIPaddIntParam(scip,
1823  "presolving/"PRESOL_NAME"/sorting",
1824  "order logicor contraints to extract big-gates before smaller ones (-1), do not order them (0) or order them to extract smaller gates at first (1)",
1825  &presoldata->sorting, TRUE, DEFAULT_SORTING, -1, 1, NULL, NULL) );
1826 
1827  return SCIP_OKAY;
1828 }
1829