Scippy

SCIP

Solving Constraint Integer Programs

cons_disjunction.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_disjunction.c
17  * @brief constraint handler for disjunction constraints
18  * @author Stefan Heinz
19  * @author Michael Winkler
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include <assert.h>
25 #include <string.h>
26 #include <limits.h>
27 
28 #include "scip/cons_disjunction.h"
29 
30 
31 /* constraint handler properties */
32 #define CONSHDLR_NAME "disjunction"
33 #define CONSHDLR_DESC "disjunction of constraints (or(cons1, cons2, ..., consn))"
34 #define CONSHDLR_ENFOPRIORITY -950000 /**< priority of the constraint handler for constraint enforcing */
35 #define CONSHDLR_CHECKPRIORITY -900000 /**< priority of the constraint handler for checking feasibility */
36 #define CONSHDLR_PROPFREQ -1 /**< frequency for propagating domains; zero means only preprocessing propagation */
37 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
38  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
39 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in
40  * (-1: no limit) */
41 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
42 #define CONSHDLR_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
43 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
44 
45 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
46 
47 
48 #define DEFAULT_ALWAYSBRANCH TRUE /**< alawys perform branching if one of the constraints is violated, otherwise only if all integers are fixed */
49 
50 /*
51  * Data structures
52  */
53 
54 /** constraint data for disjunction constraints */
55 struct SCIP_ConsData
56 {
57  SCIP_CONS** conss; /**< constraints in disjunction */
58  SCIP_CONS* relaxcons; /**< a conjunction constraint containing the linear relaxation of the
59  * disjunction constraint, or NULL
60  */
61  int consssize; /**< size of conss array */
62  int nconss; /**< number of constraints in disjunction */
63 };
64 
65 /** constraint handler data */
66 struct SCIP_ConshdlrData
67 {
68  SCIP_Bool alwaysbranch; /**< alawys perform branching if one of the constraints is violated, otherwise only if all integers are fixed */
69 };
70 
71 /*
72  * Local methods
73  */
74 
75 /** creates disjunction constraint data, captures initial constraints of disjunction */
76 static
78  SCIP* scip, /**< SCIP data structure */
79  SCIP_CONSDATA** consdata, /**< pointer to constraint data */
80  SCIP_CONS** conss, /**< initial constraint in disjunction */
81  int nconss, /**< number of initial constraints in disjunction */
82  SCIP_CONS* relaxcons /**< a conjuction constraint containing the liner relaxation of the disjunction constraint, or NULL */
83  )
84 {
85  assert(scip != NULL);
86  assert(consdata != NULL);
87 
88  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
89  if( nconss > 0 )
90  {
91  assert(conss != NULL);
92 
93  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->conss, conss, nconss) );
94 
95  (*consdata)->consssize = nconss;
96  (*consdata)->nconss = nconss;
97  (*consdata)->relaxcons = relaxcons;
98 
99  /* we need to capture the constraints to avoid that SCIP deletes them since they are not (yet) added to the
100  * problem
101  */
102  if( SCIPisTransformed(scip) )
103  {
104  SCIP_CALL( SCIPtransformConss(scip, nconss, (*consdata)->conss, (*consdata)->conss) );
105 
106  if( (*consdata)->relaxcons != NULL )
107  {
108  SCIP_CALL( SCIPtransformCons(scip, (*consdata)->relaxcons, &(*consdata)->relaxcons) );
109  }
110  }
111  else
112  {
113  int c;
114 
115  for( c = 0; c < nconss; ++c )
116  {
117  assert(conss[c] != NULL);
118  SCIP_CALL( SCIPcaptureCons(scip, conss[c]) );
119  }
120 
121  if( (*consdata)->relaxcons != NULL )
122  {
123  SCIP_CALL( SCIPcaptureCons(scip, relaxcons) );
124  }
125  }
126  }
127  else
128  {
129  (*consdata)->conss = NULL;
130  (*consdata)->consssize = 0;
131  (*consdata)->nconss = 0;
132  (*consdata)->relaxcons = NULL;
133  }
134 
135  return SCIP_OKAY;
136 }
137 
138 /** frees constraint data and releases all constraints in disjunction */
139 static
141  SCIP* scip, /**< SCIP data structure */
142  SCIP_CONSDATA** consdata /**< pointer to constraint data */
143  )
144 {
145  int c;
146 
147  assert(scip != NULL);
148  assert(consdata != NULL);
149  assert(*consdata != NULL);
150 
151  /* release constraints */
152  for( c = 0; c < (*consdata)->nconss; ++c )
153  {
154  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->conss[c]) );
155  }
156 
157  /* release relaxation constraint */
158  if( (*consdata)->relaxcons != NULL )
159  {
160  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->relaxcons) );
161  }
162 
163  /* free memory */
164  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->conss, (*consdata)->consssize);
165  SCIPfreeBlockMemory(scip, consdata);
166 
167  return SCIP_OKAY;
168 }
169 
170 /** adds constraint to disjunction */
171 static
173  SCIP* scip, /**< SCIP data structure */
174  SCIP_CONSDATA* consdata, /**< constraint data */
175  SCIP_CONS* cons /**< constraint to add to the disjunction */
176  )
177 {
178  assert(scip != NULL);
179  assert(consdata != NULL);
180  assert(cons != NULL);
181 
182  /* get memory for additional constraint */
183  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &consdata->conss, &consdata->consssize, consdata->nconss+1) );
184  assert(consdata->conss != NULL);
185  assert(consdata->nconss < consdata->consssize);
186 
187  /* insert constraint in array */
188  consdata->conss[consdata->nconss] = cons;
189  consdata->nconss++;
190 
191  if( SCIPisTransformed(scip) )
192  {
193  SCIP_CALL( SCIPtransformCons(scip, consdata->conss[consdata->nconss - 1], &(consdata->conss[consdata->nconss - 1])));
194  }
195  else
196  {
197  /* capture constraint */
198  SCIP_CALL( SCIPcaptureCons(scip, cons) );
199  }
200 
201  return SCIP_OKAY;
202 }
203 
204 /** branches on disjunctive constraint */
205 static
207  SCIP* scip, /**< SCIP data structure */
208  SCIP_CONS* cons, /**< active disjunction constraint */
209  SCIP_RESULT* result /**< pointer to store the result */
210  )
211 {
212  SCIP_CONSDATA* consdata;
213  SCIP_CONS** conss;
214  SCIP_NODE* child;
215  SCIP_Real estimate;
216  int nconss;
217  int i;
218 
219  assert(result != NULL);
220 
221  /* cannot branch on modifiable constraint */
222  if( SCIPconsIsModifiable(cons) )
223  return SCIP_OKAY;
224 
225  consdata = SCIPconsGetData(cons);
226  assert(consdata != NULL);
227 
228  conss = consdata->conss;
229  assert(conss != NULL);
230 
231  nconss = consdata->nconss;
232  assert(nconss > 0);
233 
234  estimate = SCIPgetLocalTransEstimate(scip);
235 
236  /* add all inactive constraints to local subproblem */
237  for( i = 0; i < nconss; ++i )
238  {
239  /* create the branch-and-bound tree child nodes of the current node */
240  SCIP_CALL( SCIPcreateChild(scip, &child, 0.0, estimate) );
241 
242  /* if disjunctive constraint needs to be checked, the upgraded constraint also needs to be checked */
243  if( SCIPconsIsChecked(cons) )
244  {
245  SCIP_CALL( SCIPsetConsChecked(scip, conss[i], TRUE) );
246  }
247 
248  /* add constraints to nodes */
249  SCIP_CALL( SCIPaddConsNode(scip, child, conss[i], NULL) );
250 
251  /* remove disjunction constraint, from child node */
252  SCIP_CALL( SCIPdelConsNode(scip, child, cons) );
253  }
254 
255  SCIPdebugMessage("disjunction constraint <%s> branched %d childs\n", SCIPconsGetName(cons), nconss);
256 
257  /* reset constraint age */
258  SCIP_CALL( SCIPresetConsAge(scip, cons) );
259 
260  *result = SCIP_BRANCHED;
261 
262  return SCIP_OKAY;
263 }
264 
265 /** checks disjunction constraints if at least one is feasible */
266 static
268  SCIP* scip, /**< SCIP data structure */
269  SCIP_CONS* cons, /**< active disjunction constraint */
270  SCIP_SOL* sol, /**< solution to check */
271  SCIP_Bool checkintegrality, /**< has integrality to be checked? */
272  SCIP_Bool checklprows, /**< have current LP rows to be checked? */
273  SCIP_Bool printreason, /**< should the reason for the violation be printed? */
274  SCIP_RESULT* result /**< pointer to store the result */
275  )
276 {
277  SCIP_CONSDATA* consdata;
278  SCIP_CONS** conss;
279  int nconss;
280  int i;
281 
282  assert(result != NULL);
283 
284  consdata = SCIPconsGetData(cons);
285  assert(consdata != NULL);
286 
287  conss = consdata->conss;
288  assert(conss != NULL);
289 
290  nconss = consdata->nconss;
291  assert(nconss > 0);
292 
293  *result = SCIP_INFEASIBLE;
294 
295  /* check all constraints */
296  for( i = 0; i < nconss && *result != SCIP_FEASIBLE; ++i )
297  {
298  SCIP_CALL( SCIPcheckCons(scip, conss[i], sol, checkintegrality, checklprows, FALSE, result) );
299  assert(*result == SCIP_FEASIBLE || *result == SCIP_INFEASIBLE);
300  }
301 
302  if( printreason && *result == SCIP_INFEASIBLE )
303  {
304  SCIPinfoMessage(scip, NULL, "constraint %s is violated, all sub-constraints in this disjunction are violated by this given solution\n", SCIPconsGetName(cons));
305  SCIPdebug( SCIP_CALL( SCIPprintCons(scip, cons, NULL) ) );
306  }
307 
308  return SCIP_OKAY;
309 }
310 
311 /** propagation method for disjunction constraint */
312 static
314  SCIP* scip, /**< SCIP data structure */
315  SCIP_CONS* cons, /**< disjunctive constraint */
316  int* ndelconss /**< pointer to count number of deleted constraints */
317  )
318 {
319  SCIP_CONSDATA* consdata;
320  SCIP_CONS** conss;
321  int nconss;
322  int c;
323 
324  assert(scip != NULL);
325  assert(cons != NULL);
326  assert(ndelconss != NULL);
327 
328  consdata = SCIPconsGetData(cons);
329  assert(consdata != NULL);
330 
331  conss = consdata->conss;
332  assert(conss != NULL);
333 
334  nconss = consdata->nconss;
335  assert(nconss >= 1);
336 
337  for( c = 0; c < nconss; ++c )
338  {
339  /* if a constraint of the disjunction is already active, the disjunction is enforce by this constraint and
340  * therefore redundant and can be locally deleted
341  */
342  if( SCIPconsIsActive(conss[c]) )
343  {
344  /* if we can globally delete the whole disjunctive constraint, because one constraint is already active, we
345  * might need to update the check stage
346  */
347  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING || SCIPgetNNodes(scip) == 0 )
348  {
349  /* if disjunctive constraint needs to be checked, the upgraded constraint also needs to be checked */
350  if( SCIPconsIsChecked(cons) )
351  {
352  SCIP_CALL( SCIPsetConsChecked(scip, conss[c], TRUE) );
353  }
354  }
355 
356  (*ndelconss)++;
357  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
358  break;
359  }
360  /* if a sub-constraint is globally deleted, it means that this constraint is redundant and always fulfilled and
361  * this makes also this disjunction redundant
362  */
363  else if( SCIPconsIsDeleted(conss[c]) )
364  {
365  (*ndelconss)++;
366  SCIP_CALL( SCIPdelCons(scip, cons) );
367  break;
368  }
369  }
370 
371  return SCIP_OKAY;
372 }
373 
374 /*
375  * Callback methods of constraint handler
376  */
377 
378 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
379 static
380 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyDisjunction)
381 { /*lint --e{715}*/
382  assert(scip != NULL);
383  assert(conshdlr != NULL);
384  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
385 
386  /* call inclusion method of constraint handler */
388 
389  *valid = TRUE;
390 
391  return SCIP_OKAY;
392 }
393 
394 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
395 static
396 SCIP_DECL_CONSFREE(consFreeDisjunction)
397 {
398  SCIP_CONSHDLRDATA* conshdlrdata;
399 
400  assert(scip != NULL);
401  assert(conshdlr != NULL);
402  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
403 
404  /* free constraint handler data */
405  conshdlrdata = SCIPconshdlrGetData(conshdlr);
406  assert(conshdlrdata != NULL);
407 
408  SCIPfreeMemory(scip, &conshdlrdata);
409 
410  SCIPconshdlrSetData(conshdlr, NULL);
411 
412  return SCIP_OKAY;
413 }
414 
415 /** frees specific constraint data */
416 static
417 SCIP_DECL_CONSDELETE(consDeleteDisjunction)
418 { /*lint --e{715}*/
419  SCIP_CALL( consdataFree(scip, consdata) );
420 
421  return SCIP_OKAY;
422 }
423 
424 
425 /** transforms constraint data into data belonging to the transformed problem */
426 static
427 SCIP_DECL_CONSTRANS(consTransDisjunction)
428 { /*lint --e{715}*/
429  SCIP_CONSDATA* sourcedata;
430  SCIP_CONSDATA* targetdata;
431 
432  /* get constraint data of source constraint */
433  sourcedata = SCIPconsGetData(sourcecons);
434  assert(sourcedata != NULL);
435 
436  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->conss, sourcedata->nconss, sourcedata->relaxcons) );
437 
438  /* create target constraint */
439  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
440  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
441  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
442  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
443  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
444 
445  return SCIP_OKAY;
446 }
447 
448 /** LP initialization method of constraint handler */
449 static
450 SCIP_DECL_CONSINITLP(consInitlpDisjunction)
451 { /*lint --e{715}*/
452  SCIP_CONSDATA* consdata;
453  int c;
454 
455  for( c = 0; c < nconss; ++c )
456  {
457  consdata = SCIPconsGetData(conss[c]);
458  assert(consdata != NULL);
459 
460  /* if we have a relaxation constraint and it is not active, then we add it locally */
461  if( consdata->relaxcons != NULL && !SCIPconsIsActive(consdata->relaxcons) )
462  {
463  SCIP_CALL( SCIPaddConsLocal(scip, consdata->relaxcons, NULL) );
464  }
465  }
466 
467  return SCIP_OKAY;
468 }
469 
470 
471 /** constraint enforcing method of constraint handler for LP solutions */
472 static
473 SCIP_DECL_CONSENFOLP(consEnfolpDisjunction)
474 { /*lint --e{715}*/
475  SCIP_CONSHDLRDATA* conshdlrdata;
477  int c;
478 
479  *result = SCIP_FEASIBLE;
480 
481  conshdlrdata = SCIPconshdlrGetData(conshdlr);
482  assert(conshdlrdata != NULL);
483 
484  branch = SCIPgetNPseudoBranchCands(scip) == 0 || conshdlrdata->alwaysbranch;
485 
486  for( c = 0; c < nconss && *result != SCIP_BRANCHED; ++c )
487  {
488  /* check the disjunction */
489  SCIP_CALL( checkCons(scip, conss[c], NULL, FALSE, FALSE, FALSE, result) );
490 
491  if( *result == SCIP_INFEASIBLE && branch )
492  {
493  SCIP_CALL( branchCons(scip, conss[c], result) );
494  }
495  }
496 
497  return SCIP_OKAY;
498 }
499 
500 
501 /** constraint enforcing method of constraint handler for pseudo solutions */
502 static
503 SCIP_DECL_CONSENFOPS(consEnfopsDisjunction)
504 { /*lint --e{715}*/
505  SCIP_CONSHDLRDATA* conshdlrdata;
507  int c;
508 
509  *result = SCIP_FEASIBLE;
510 
511  conshdlrdata = SCIPconshdlrGetData(conshdlr);
512  assert(conshdlrdata != NULL);
513 
514  branch = SCIPgetNPseudoBranchCands(scip) == 0 || conshdlrdata->alwaysbranch;
515 
516  for( c = 0; c < nconss && *result != SCIP_BRANCHED; ++c )
517  {
518  /* check the disjunction */
519  SCIP_CALL( checkCons(scip, conss[c], NULL, FALSE, FALSE, FALSE, result) );
520 
521  if( *result == SCIP_INFEASIBLE && branch )
522  {
523  SCIP_CALL( branchCons(scip, conss[c], result) );
524  }
525  }
526 
527  return SCIP_OKAY;
528 }
529 
530 
531 /** feasibility check method of constraint handler for integral solutions */
532 static
533 SCIP_DECL_CONSCHECK(consCheckDisjunction)
534 { /*lint --e{715}*/
535  int c;
536 
537  *result = SCIP_FEASIBLE;
538 
539  for( c = 0; c < nconss && *result == SCIP_FEASIBLE; ++c )
540  {
541  /* check the disjunction */
542  SCIP_CALL( checkCons(scip, conss[c], sol, checkintegrality, checklprows, printreason, result) );
543  assert(*result == SCIP_FEASIBLE || *result == SCIP_INFEASIBLE);
544  }
545 
546  return SCIP_OKAY;
547 }
548 
549 
550 /** domain propagation method of constraint handler */
551 static
552 SCIP_DECL_CONSPROP(consPropDisjunction)
553 { /*lint --e{715}*/
554  int ndelconss;
555  int c;
556 
557  ndelconss = 0;
558 
559  /* in probing mode we do not for deletable constraints */
560  if( !SCIPinProbing(scip) )
561  {
562  for( c = 0; c < nconss; ++c )
563  {
564  /* propagate constraint */
565  SCIP_CALL( propagateCons(scip, conss[c], &ndelconss) );
566  }
567  }
568 
569  /* adjust result code */
570  if( ndelconss > 0 )
571  *result = SCIP_REDUCEDDOM;
572  else
573  *result = SCIP_DIDNOTFIND;
574 
575  return SCIP_OKAY;
576 }
577 
578 
579 /** presolving method of constraint handler */
580 static
581 SCIP_DECL_CONSPRESOL(consPresolDisjunction)
582 { /*lint --e{715}*/
583  SCIP_CONSDATA* consdata;
584  int oldndelconss;
585  int c;
586 
587  assert(result != NULL);
588 
589  *result = SCIP_DIDNOTFIND;
590  oldndelconss = *ndelconss;
591 
592  /* all disjunction constraints with one constraint can be replaced with that corresponding constraint */
593  for( c = 0; c < nconss; ++c )
594  {
595  consdata = SCIPconsGetData(conss[c]);
596  assert(consdata != NULL);
597 
598  if( !SCIPconsIsModifiable(conss[c]) && consdata->nconss == 1 )
599  {
600  /* add constraint to the problem */
601  if( !SCIPconsIsActive(consdata->conss[0]) )
602  {
603  SCIP_CONS* subcons = consdata->conss[0];
604 
605  /* if disjunctive constraint needs to be checked, the upgraded constraint also needs to be checked */
606  if( SCIPconsIsChecked(conss[c]) )
607  {
608  SCIP_CALL( SCIPsetConsChecked(scip, subcons, TRUE) );
609  }
610 
611  SCIP_CALL( SCIPaddCons(scip, subcons) );
612  }
613 
614  /* remove disjunction constraint */
615  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
616 
617  *result = SCIP_SUCCESS;
618 
619  continue;
620  }
621 
622  /* propagate constraint */
623  SCIP_CALL( propagateCons(scip, conss[c], ndelconss) );
624  }
625 
626  if( *ndelconss > oldndelconss )
627  *result = SCIP_SUCCESS;
628 
629  return SCIP_OKAY;
630 }
631 
632 
633 /** variable rounding lock method of constraint handler */
634 static
635 SCIP_DECL_CONSLOCK(consLockDisjunction)
636 { /*lint --e{715}*/
637  SCIP_CONSDATA* consdata;
638  int c;
639 
640  consdata = SCIPconsGetData(cons);
641  assert(consdata != NULL);
642 
643  /* lock sub constraints */
644  for( c = 0; c < consdata->nconss; ++c )
645  {
646  SCIP_CALL( SCIPaddConsLocks(scip, consdata->conss[c], nlockspos, nlocksneg) );
647  }
648 
649  return SCIP_OKAY;
650 }
651 
652 
653 /** constraint display method of constraint handler */
654 static
655 SCIP_DECL_CONSPRINT(consPrintDisjunction)
656 { /*lint --e{715}*/
657  SCIP_CONSDATA* consdata;
658  int i;
659 
660  assert(scip != NULL);
661  assert(conshdlr != NULL);
662  assert(cons != NULL);
663 
664  consdata = SCIPconsGetData(cons);
665  assert(consdata != NULL);
666 
667  SCIPinfoMessage(scip, file, "disjunction(");
668 
669  for( i = 0; i < consdata->nconss; ++i )
670  {
671  if( i > 0 )
672  SCIPinfoMessage(scip, file, ", ");
673  SCIP_CALL( SCIPprintCons(scip, consdata->conss[i], file) );
674  }
675 
676  /* print relaxation */
677  if( consdata->relaxcons != NULL )
678  {
679  SCIPinfoMessage(scip, file, ",, ");
680  SCIP_CALL( SCIPprintCons(scip, consdata->relaxcons, file) );
681  }
682 
683  SCIPinfoMessage(scip, file, ")");
684 
685  return SCIP_OKAY;
686 }
687 
688 /** constraint parsing method of constraint handler */
689 static
690 SCIP_DECL_CONSPARSE(consParseDisjunction)
691 { /*lint --e{715}*/
692  SCIP_CONS** conss;
693  SCIP_Bool relaxed = FALSE;
694  int nconss;
695  int sconss;
696  char* token;
697  char* saveptr;
698  char* nexttokenstart;
699  char* copystr;
700 
701  assert(scip != NULL);
702  assert(conshdlr != NULL);
703  assert(cons != NULL);
704  assert(success != NULL);
705  assert(str != NULL);
706  assert(name != NULL);
707 
708  SCIPdebugMessage("parsing disjunction <%s>\n", name);
709 
710  *success = TRUE;
711 
712  /* allocate memory for constraint in disjunction, initial size is set to 10 */
713  nconss = 0;
714  sconss = 10;
715  SCIP_CALL( SCIPallocBufferArray(scip, &conss, sconss) );
716  SCIP_CALL( SCIPduplicateBufferArray(scip, &copystr, str, (int)strlen(str)+1) );
717 
718  /* find '(' at the beginning, string should start with 'disjunction(' */
719  saveptr = strpbrk(copystr, "("); /*lint !e158*/
720 
721  if( saveptr == NULL )
722  {
723  SCIPdebugMessage("error parsing disjunctive constraint: \"%s\"\n", str);
724  *success = FALSE;
725  goto TERMINATE;
726  }
727 
728  /* skip '(' */
729  ++saveptr;
730  /* remember token start position */
731  nexttokenstart = saveptr;
732 
733  /* brackets '(' and ')' can exist co we check for them and the constraint delimeter */
734  saveptr = strpbrk(saveptr, "(,");
735 
736  /* brackets '(' and ')' can exist in the rest of the string so we need to skip them to find the end of the first
737  * sub-constraint marked by a ','
738  */
739  if( saveptr != NULL )
740  {
741  do
742  {
743  int bracketcounter = 0;
744 
745  if( *saveptr == '(' )
746  {
747  do
748  {
749  ++bracketcounter;
750  ++saveptr;
751 
752  /* find last ending bracket */
753  while( bracketcounter > 0 )
754  {
755  saveptr = strpbrk(saveptr, "()");
756 
757  if( saveptr != NULL )
758  {
759  if( *saveptr == '(' )
760  ++bracketcounter;
761  else
762  --bracketcounter;
763 
764  ++saveptr;
765  }
766  else
767  {
768  SCIPdebugMessage("error parsing disjunctive constraint: \"%s\"\n", str);
769  *success = FALSE;
770  goto TERMINATE;
771  }
772  }
773 
774  saveptr = strpbrk(saveptr, "(,");
775  }
776  while( saveptr != NULL && *saveptr == '(' );
777  }
778 
779  /* we found a ',' so the end of the first sub-constraint is determined */
780  if( saveptr != NULL )
781  {
782  assert(*saveptr == ',');
783 
784  /* resize constraint array if necessary */
785  if( nconss == sconss )
786  {
787  sconss = SCIPcalcMemGrowSize(scip, nconss+1);
788  assert(nconss < sconss);
789 
790  SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) );
791  }
792 
793  assert(saveptr > nexttokenstart);
794 
795  /* extract token for parsing */
796  SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) );
797  token[saveptr - nexttokenstart] = '\0';
798 
799  SCIPdebugMessage("disjunctive parsing token(constraint): %s\n", token);
800 
801  /* parsing a constraint, part of the disjunction */
802  SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, FALSE, propagate, TRUE, modifiable, dynamic, removable, stickingatnode, success) );
803 
804  SCIPfreeBufferArray(scip, &token);
805 
806  if( *success )
807  ++nconss;
808  else
809  {
810  SCIPdebugMessage("error parsing disjunctive constraint: \"%s\"\n", str);
811  goto TERMINATE;
812  }
813  /* skip ',' delimeter */
814  ++saveptr;
815  /* remember token start position */
816  nexttokenstart = saveptr;
817 
818  /* check if we found the last constraint, which is a conjunctive relaxation of the disjunction, and in the
819  * CIP format marked by two consecutive ','
820  */
821  if( *nexttokenstart == ',' )
822  {
823  /* remember token start position */
824  nexttokenstart = saveptr+1;
825 
826  relaxed = TRUE;
827  break;
828  }
829 
830  saveptr = strpbrk(saveptr, "(,");
831  }
832  }
833  while( saveptr != NULL );
834  }
835 
836  /* find end of disjunction constraint */
837  saveptr = strrchr(nexttokenstart, ')');
838 
839  if( saveptr == NULL )
840  {
841  SCIPdebugMessage("error parsing disjunctive constraint: \"%s\"\n", str);
842  *success = FALSE;
843  goto TERMINATE;
844  }
845  /* parse last sub-constraint */
846  else
847  {
848  /* resize constraint array if necessary */
849  if( nconss == sconss )
850  {
851  ++sconss;
852  SCIP_CALL( SCIPreallocBufferArray(scip, &conss, sconss) );
853  }
854 
855  assert(saveptr > nexttokenstart);
856 
857  /* extract token for parsing */
858  SCIP_CALL( SCIPduplicateBufferArray(scip, &token, nexttokenstart, saveptr - nexttokenstart + 1) );
859  token[saveptr - nexttokenstart] = '\0';
860 
861  SCIPdebugMessage("disjunctive parsing token(constraint): %s\n", token);
862 
863  /* parsing a constraint, part of the disjunction */
864  SCIP_CALL( SCIPparseCons(scip, &(conss[nconss]), token, initial, separate, enforce, FALSE, propagate, TRUE, modifiable, dynamic, removable, stickingatnode, success) );
865 
866  if( *success )
867  ++nconss;
868 
869  SCIPfreeBufferArray(scip, &token);
870  }
871  assert(nconss > 0 || !(*success));
872 
873  /* if parsing sub-constraints was fine, create the disjunctive constraint */
874  if( *success )
875  {
876  /* create disjunctive constraint */
877  SCIP_CALL( SCIPcreateConsDisjunction(scip, cons, name, relaxed ? nconss - 1: nconss, conss, relaxed ? conss[nconss - 1] : NULL,
878  initial, enforce, check, local, modifiable, dynamic) );
879  }
880 
881  /* free parsed constraints */
882  for( --nconss; nconss >= 0; --nconss )
883  {
884  SCIP_CALL( SCIPreleaseCons(scip, &conss[nconss]) );
885  }
886 
887  TERMINATE:
888  /* free temporary memory */
889  SCIPfreeBufferArray(scip, &copystr);
890  SCIPfreeBufferArray(scip, &conss);
891 
892  return SCIP_OKAY;
893 }
894 
895 
896 /** constraint copying method of constraint handler */
897 static
898 SCIP_DECL_CONSCOPY(consCopyDisjunction)
899 { /*lint --e{715}*/
900  SCIP_CONSDATA* sourcedata;
901  SCIP_CONS** sourceconss;
902  SCIP_CONS** conss;
903  int nconss;
904  int c;
905 
906  *valid = TRUE;
907 
908  sourcedata = SCIPconsGetData(sourcecons);
909  assert(sourcedata != NULL);
910 
911  nconss = sourcedata->nconss;
912 
913  SCIP_CALL( SCIPallocBufferArray(scip, &conss, nconss) );
914  sourceconss = sourcedata->conss;
915 
916  /* copy each constraint one by one */
917  for( c = 0; c < nconss && (*valid); ++c )
918  {
919  SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourceconss[c], &conss[c], SCIPconsGetHdlr(sourceconss[c]),
920  varmap, consmap, SCIPconsGetName(sourceconss[c]),
921  SCIPconsIsInitial(sourceconss[c]), SCIPconsIsSeparated(sourceconss[c]), SCIPconsIsEnforced(sourceconss[c]),
922  SCIPconsIsChecked(sourceconss[c]), SCIPconsIsPropagated(sourceconss[c]),
923  SCIPconsIsLocal(sourceconss[c]), SCIPconsIsModifiable(sourceconss[c]),
924  SCIPconsIsDynamic(sourceconss[c]), SCIPconsIsRemovable(sourceconss[c]), SCIPconsIsStickingAtNode(sourceconss[c]),
925  global, valid) );
926  assert(!(*valid) || conss[c] != NULL);
927  }
928 
929  if( *valid )
930  {
931  SCIP_CONS* relaxcons;
932 
933  relaxcons = sourcedata->relaxcons;
934 
935  if( relaxcons != NULL )
936  {
937  SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, relaxcons, &relaxcons, SCIPconsGetHdlr(relaxcons),
938  varmap, consmap, SCIPconsGetName(relaxcons),
939  SCIPconsIsInitial(relaxcons), SCIPconsIsSeparated(relaxcons), SCIPconsIsEnforced(relaxcons),
940  SCIPconsIsChecked(relaxcons), SCIPconsIsPropagated(relaxcons),
941  SCIPconsIsLocal(relaxcons), SCIPconsIsModifiable(relaxcons),
942  SCIPconsIsDynamic(relaxcons), SCIPconsIsRemovable(relaxcons), SCIPconsIsStickingAtNode(relaxcons),
943  global, valid) );
944  }
945 
946  if( *valid )
947  {
948  SCIP_CALL( SCIPcreateConsDisjunction(scip, cons, name, nconss, conss, relaxcons,
949  initial, enforce, check, local, modifiable, dynamic) );
950 
951  SCIP_CALL( SCIPreleaseCons(scip, &relaxcons) );
952  }
953  }
954 
955  /* release the copied constraints */
956  for( c = (*valid ? c - 1 : c - 2); c >= 0; --c )
957  {
958  assert(conss[c] != NULL);
959  SCIP_CALL( SCIPreleaseCons(scip, &conss[c]) );
960  }
961 
962  SCIPfreeBufferArray(scip, &conss);
963 
964  return SCIP_OKAY;
965 }
966 
967 
968 /*
969  * constraint specific interface methods
970  */
971 
972 /** creates the handler for disjunction constraints and includes it in SCIP */
974  SCIP* scip /**< SCIP data structure */
975  )
976 {
977  SCIP_CONSHDLRDATA* conshdlrdata;
978  SCIP_CONSHDLR* conshdlr;
979 
980  /* create disjunction constraint handler data */
981  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
982 
983  /* include constraint handler */
986  consEnfolpDisjunction, consEnfopsDisjunction, consCheckDisjunction, consLockDisjunction,
987  conshdlrdata) );
988 
989  assert(conshdlr != NULL);
990 
991  /* set non-fundamental callbacks via specific setter functions */
992  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyDisjunction, consCopyDisjunction) );
993  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeDisjunction) );
994  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteDisjunction) );
995  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpDisjunction) );
996  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseDisjunction) );
997  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolDisjunction, CONSHDLR_MAXPREROUNDS,
999  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintDisjunction) );
1000  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropDisjunction, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
1002  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransDisjunction) );
1003 
1004 
1006  "constraints/"CONSHDLR_NAME"/alwaysbranch",
1007  "alawys perform branching if one of the constraints is violated, otherwise only if all integers are fixed",
1008  &conshdlrdata->alwaysbranch, FALSE, DEFAULT_ALWAYSBRANCH, NULL, NULL) );
1009 
1010  return SCIP_OKAY;
1011 }
1012 
1013 /** creates and captures a disjunction constraint
1014  *
1015  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
1016  */
1018  SCIP* scip, /**< SCIP data structure */
1019  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1020  const char* name, /**< name of constraint */
1021  int nconss, /**< number of initial constraints in disjunction */
1022  SCIP_CONS** conss, /**< initial constraint in disjunction */
1023  SCIP_CONS* relaxcons, /**< a conjunction constraint containing the linear relaxation of the disjunction constraint, or NULL */
1024  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1025  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1026  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1027  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1028  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1029  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1030  SCIP_Bool local, /**< is constraint only valid locally?
1031  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1032  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1033  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1034  * adds coefficients to this constraint. */
1035  SCIP_Bool dynamic /**< is constraint subject to aging?
1036  * Usually set to FALSE. Set to TRUE for own cuts which
1037  * are separated as constraints. */
1038  )
1039 {
1040  SCIP_CONSHDLR* conshdlr;
1041  SCIP_CONSDATA* consdata;
1042 
1043  /* find the disjunction constraint handler */
1044  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
1045  if( conshdlr == NULL )
1046  {
1047  SCIPerrorMessage("disjunction constraint handler not found\n");
1048  return SCIP_PLUGINNOTFOUND;
1049  }
1050 
1051  /* create constraint data */
1052  SCIP_CALL( consdataCreate(scip, &consdata, conss, nconss, relaxcons) );
1053 
1054  /* create constraint */
1055  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, FALSE, enforce, check, FALSE,
1056  local, modifiable, dynamic, FALSE, FALSE) );
1057 
1058  return SCIP_OKAY;
1059 }
1060 
1061 /** creates and captures a cumulative constraint
1062  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
1063  * method SCIPcreateConsDisjunction(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
1064  *
1065  * @see SCIPcreateConsDisjunction() for information about the basic constraint flag configuration
1066  *
1067  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
1068  */
1070  SCIP* scip, /**< SCIP data structure */
1071  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1072  const char* name, /**< name of constraint */
1073  int nconss, /**< number of initial constraints in disjunction */
1074  SCIP_CONS** conss, /**< initial constraint in disjunction */
1075  SCIP_CONS* relaxcons /**< a conjunction constraint containing the linear relaxation of the disjunction constraint, or NULL */
1076  )
1077 {
1078  assert(scip != NULL);
1079 
1080  SCIP_CALL( SCIPcreateConsDisjunction(scip, cons, name, nconss, conss, relaxcons,
1081  TRUE, TRUE, TRUE, FALSE, FALSE, FALSE) );
1082 
1083  return SCIP_OKAY;
1084 }
1085 
1086 
1087 /** adds constraint to the disjunction of constraints */
1089  SCIP* scip, /**< SCIP data structure */
1090  SCIP_CONS* cons, /**< disjunction constraint */
1091  SCIP_CONS* addcons /**< additional constraint in disjunction */
1092  )
1093 {
1094  SCIP_CONSDATA* consdata;
1095 
1096  assert(cons != NULL);
1097  assert(addcons != NULL);
1098 
1099  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
1100  {
1101  SCIPerrorMessage("constraint is not a disjunction constraint\n");
1102  return SCIP_INVALIDDATA;
1103  }
1104 
1105  consdata = SCIPconsGetData(cons);
1106  assert(consdata != NULL);
1107 
1108  SCIP_CALL( consdataAddCons(scip, consdata, addcons) );
1109 
1110  return SCIP_OKAY;
1111 
1112 }
1113 
1114