1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*  Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SCIP; see the file LICENSE. If not visit scipopt.org.         */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file   cons_or.c
26   	 * @ingroup DEFPLUGINS_CONS
27   	 * @brief  Constraint handler for "or" constraints,  \f$r = x_1 \vee x_2 \vee \dots  \vee x_n\f$
28   	 * @author Tobias Achterberg
29   	 * @author Stefan Heinz
30   	 * @author Michael Winkler
31   	 *
32   	 * This constraint handler deals with "or" constraint. These are constraint of the form:
33   	 *
34   	 * \f[
35   	 *    r = x_1 \vee x_2 \vee \dots  \vee x_n
36   	 * \f]
37   	 *
38   	 * where \f$x_i\f$ is a binary variable for all \f$i\f$. Hence, \f$r\f$ is also of binary type. The variable \f$r\f$ is
39   	 * called resultant and the \f$x\f$'s operators.
40   	 */
41   	
42   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
43   	
44   	#include "blockmemshell/memory.h"
45   	#include "scip/cons_and.h"
46   	#include "scip/cons_or.h"
47   	#include "scip/pub_cons.h"
48   	#include "scip/pub_event.h"
49   	#include "scip/pub_lp.h"
50   	#include "scip/pub_message.h"
51   	#include "scip/pub_misc.h"
52   	#include "scip/pub_var.h"
53   	#include "scip/scip_conflict.h"
54   	#include "scip/scip_cons.h"
55   	#include "scip/scip_copy.h"
56   	#include "scip/scip_cut.h"
57   	#include "scip/scip_event.h"
58   	#include "scip/scip_general.h"
59   	#include "scip/scip_lp.h"
60   	#include "scip/scip_mem.h"
61   	#include "scip/scip_message.h"
62   	#include "scip/scip_numerics.h"
63   	#include "scip/scip_prob.h"
64   	#include "scip/scip_probing.h"
65   	#include "scip/scip_sol.h"
66   	#include "scip/scip_tree.h"
67   	#include "scip/scip_var.h"
68   	#include "scip/symmetry_graph.h"
69   	#include "symmetry/struct_symmetry.h"
70   	#include <string.h>
71   	
72   	
73   	/* constraint handler properties */
74   	#define CONSHDLR_NAME          "or"
75   	#define CONSHDLR_DESC          "constraint handler for or constraints: r = or(x1, ..., xn)"
76   	#define CONSHDLR_SEPAPRIORITY   +850000 /**< priority of the constraint handler for separation */
77   	#define CONSHDLR_ENFOPRIORITY   -850000 /**< priority of the constraint handler for constraint enforcing */
78   	#define CONSHDLR_CHECKPRIORITY  -850000 /**< priority of the constraint handler for checking feasibility */
79   	#define CONSHDLR_SEPAFREQ             0 /**< frequency for separating cuts; zero means to separate only in the root node */
80   	#define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
81   	#define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
82   	                                         *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
83   	#define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
84   	#define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
85   	#define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
86   	#define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
87   	
88   	#define CONSHDLR_PROP_TIMING             SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
89   	#define CONSHDLR_PRESOLTIMING            SCIP_PRESOLTIMING_MEDIUM /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
90   	
91   	#define EVENTHDLR_NAME         "or"
92   	#define EVENTHDLR_DESC         "event handler for or constraints"
93   	
94   	
95   	/*
96   	 * Data structures
97   	 */
98   	
99   	/** constraint data for or constraints */
100  	struct SCIP_ConsData
101  	{
102  	   SCIP_VAR**            vars;               /**< variables in the or operation */
103  	   SCIP_VAR*             resvar;             /**< resultant variable */
104  	   SCIP_ROW**            rows;               /**< rows for linear relaxation of or constraint */
105  	   int                   nvars;              /**< number of variables in or operation */
106  	   int                   varssize;           /**< size of vars array */
107  	   int                   rowssize;           /**< size of rows array */
108  	   int                   watchedvar1;        /**< position of first watched operator variable */
109  	   int                   watchedvar2;        /**< position of second watched operator variable */
110  	   int                   filterpos1;         /**< event filter position of first watched operator variable */
111  	   int                   filterpos2;         /**< event filter position of second watched operator variable */
112  	   unsigned int          propagated:1;       /**< is constraint already preprocessed/propagated? */
113  	   unsigned int          nofixedone:1;       /**< is none of the operator variables fixed to TRUE? */
114  	   unsigned int          impladded:1;        /**< were the implications of the constraint already added? */
115  	   unsigned int          opimpladded:1;      /**< was the implication for 2 operands with fixed resultant added? */
116  	};
117  	
118  	/** constraint handler data */
119  	struct SCIP_ConshdlrData
120  	{
121  	   SCIP_EVENTHDLR*       eventhdlr;          /**< event handler for events on watched variables */
122  	};
123  	
124  	
125  	/*
126  	 * Propagation rules
127  	 */
128  	
129  	enum Proprule
130  	{
131  	   PROPRULE_1       = 0,                     /**< v_i = TRUE                                   =>  r   = TRUE            */
132  	   PROPRULE_2       = 1,                     /**< r   = FALSE                                  =>  v_i = FALSE for all i */
133  	   PROPRULE_3       = 2,                     /**< v_i = FALSE for all i                        =>  r   = FALSE           */
134  	   PROPRULE_4       = 3,                     /**< r   = TRUE, v_i = FALSE for all i except j   =>  v_j = TRUE            */
135  	   PROPRULE_INVALID = 4                      /**< propagation was applied without a specific propagation rule */
136  	};
137  	typedef enum Proprule PROPRULE;
138  	
139  	
140  	/*
141  	 * Local methods
142  	 */
143  	
144  	/** installs rounding locks for the given variable in the given or constraint */
145  	static
146  	SCIP_RETCODE lockRounding(
147  	   SCIP*                 scip,               /**< SCIP data structure */
148  	   SCIP_CONS*            cons,               /**< or constraint */
149  	   SCIP_VAR*             var                 /**< variable of constraint entry */
150  	   )
151  	{
152  	   assert(!SCIPconsIsLockedType(cons, SCIP_LOCKTYPE_CONFLICT));
153  	
154  	   /* rounding in both directions may violate the constraint */
155  	   SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
156  	
157  	   return SCIP_OKAY;
158  	}
159  	
160  	/** removes rounding locks for the given variable in the given or constraint */
161  	static
162  	SCIP_RETCODE unlockRounding(
163  	   SCIP*                 scip,               /**< SCIP data structure */
164  	   SCIP_CONS*            cons,               /**< or constraint */
165  	   SCIP_VAR*             var                 /**< variable of constraint entry */
166  	   )
167  	{
168  	   assert(!SCIPconsIsLockedType(cons, SCIP_LOCKTYPE_CONFLICT));
169  	
170  	   /* rounding in both directions may violate the constraint */
171  	   SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
172  	
173  	   return SCIP_OKAY;
174  	}
175  	
176  	/** creates constraint handler data */
177  	static
178  	SCIP_RETCODE conshdlrdataCreate(
179  	   SCIP*                 scip,               /**< SCIP data structure */
180  	   SCIP_CONSHDLRDATA**   conshdlrdata,       /**< pointer to store the constraint handler data */
181  	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
182  	   )
183  	{
184  	   assert(scip != NULL);
185  	   assert(conshdlrdata != NULL);
186  	   assert(eventhdlr != NULL);
187  	
188  	   SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
189  	
190  	   /* set event handler for catching events on watched variables */
191  	   (*conshdlrdata)->eventhdlr = eventhdlr;
192  	
193  	   return SCIP_OKAY;
194  	}
195  	
196  	/** frees constraint handler data */
197  	static
198  	void conshdlrdataFree(
199  	   SCIP*                 scip,               /**< SCIP data structure */
200  	   SCIP_CONSHDLRDATA**   conshdlrdata        /**< pointer to the constraint handler data */
201  	   )
202  	{
203  	   assert(conshdlrdata != NULL);
204  	   assert(*conshdlrdata != NULL);
205  	
206  	   SCIPfreeBlockMemory(scip, conshdlrdata);
207  	}
208  	
209  	/** gets number of LP rows needed for the LP relaxation of the constraint */
210  	static
211  	int consdataGetNRows(
212  	   SCIP_CONSDATA*        consdata            /**< constraint data */
213  	   )
214  	{
215  	   assert(consdata != NULL);
216  	
217  	   return consdata->nvars + 1;
218  	}
219  	
220  	/** catches events for the watched variable at given position */
221  	static
222  	SCIP_RETCODE consdataCatchWatchedEvents(
223  	   SCIP*                 scip,               /**< SCIP data structure */
224  	   SCIP_CONSDATA*        consdata,           /**< or constraint data */
225  	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
226  	   int                   pos,                /**< array position of variable to catch bound change events for */
227  	   int*                  filterpos           /**< pointer to store position of event filter entry */
228  	   )
229  	{
230  	   assert(consdata != NULL);
231  	   assert(consdata->vars != NULL);
232  	   assert(eventhdlr != NULL);
233  	   assert(0 <= pos && pos < consdata->nvars);
234  	   assert(filterpos != NULL);
235  	
236  	   /* catch tightening events for upper bound and relaxed events for lower bounds on watched variable */
237  	   SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[pos], SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_LBRELAXED,
238  	         eventhdlr, (SCIP_EVENTDATA*)consdata, filterpos) );
239  	
240  	   return SCIP_OKAY;
241  	}
242  	
243  	
244  	/** drops events for the watched variable at given position */
245  	static
246  	SCIP_RETCODE consdataDropWatchedEvents(
247  	   SCIP*                 scip,               /**< SCIP data structure */
248  	   SCIP_CONSDATA*        consdata,           /**< or constraint data */
249  	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
250  	   int                   pos,                /**< array position of watched variable to drop bound change events for */
251  	   int                   filterpos           /**< position of event filter entry */
252  	   )
253  	{
254  	   assert(consdata != NULL);
255  	   assert(consdata->vars != NULL);
256  	   assert(eventhdlr != NULL);
257  	   assert(0 <= pos && pos < consdata->nvars);
258  	   assert(filterpos >= 0);
259  	
260  	   /* drop tightening events for upper bound and relaxed events for lower bounds on watched variable */
261  	   SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_LBRELAXED,
262  	         eventhdlr, (SCIP_EVENTDATA*)consdata, filterpos) );
263  	
264  	   return SCIP_OKAY;
265  	}
266  	
267  	/** catches needed events on all variables of constraint, except the special ones for watched variables */
268  	static
269  	SCIP_RETCODE consdataCatchEvents(
270  	   SCIP*                 scip,               /**< SCIP data structure */
271  	   SCIP_CONSDATA*        consdata,           /**< or constraint data */
272  	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
273  	   )
274  	{
275  	   int i;
276  	
277  	   assert(consdata != NULL);
278  	
279  	   /* catch bound change events for both bounds on resultant variable */
280  	   SCIP_CALL( SCIPcatchVarEvent(scip, consdata->resvar, SCIP_EVENTTYPE_BOUNDCHANGED,
281  	         eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
282  	
283  	   /* catch tightening events for lower bound and relaxed events for upper bounds on operator variables */
284  	   for( i = 0; i < consdata->nvars; ++i )
285  	   {
286  	      SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[i], SCIP_EVENTTYPE_LBTIGHTENED | SCIP_EVENTTYPE_UBRELAXED,
287  	            eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
288  	   }
289  	
290  	   return SCIP_OKAY;
291  	}
292  	
293  	/** drops events on all variables of constraint, except the special ones for watched variables */
294  	static
295  	SCIP_RETCODE consdataDropEvents(
296  	   SCIP*                 scip,               /**< SCIP data structure */
297  	   SCIP_CONSDATA*        consdata,           /**< or constraint data */
298  	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
299  	   )
300  	{
301  	   int i;
302  	
303  	   assert(consdata != NULL);
304  	
305  	   /* drop bound change events for both bounds on resultant variable */
306  	   SCIP_CALL( SCIPdropVarEvent(scip, consdata->resvar, SCIP_EVENTTYPE_BOUNDCHANGED,
307  	         eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
308  	
309  	   /* drop tightening events for lower bound and relaxed events for upper bounds on operator variables */
310  	   for( i = 0; i < consdata->nvars; ++i )
311  	   {
312  	      SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[i], SCIP_EVENTTYPE_LBTIGHTENED | SCIP_EVENTTYPE_UBRELAXED,
313  	            eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
314  	   }
315  	
316  	   return SCIP_OKAY;
317  	}
318  	
319  	/** stores the given variable numbers as watched variables, and updates the event processing */
320  	static
321  	SCIP_RETCODE consdataSwitchWatchedvars(
322  	   SCIP*                 scip,               /**< SCIP data structure */
323  	   SCIP_CONSDATA*        consdata,           /**< or constraint data */
324  	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
325  	   int                   watchedvar1,        /**< new first watched variable */
326  	   int                   watchedvar2         /**< new second watched variable */
327  	   )
328  	{
329  	   assert(consdata != NULL);
330  	   assert(watchedvar1 == -1 || watchedvar1 != watchedvar2);
331  	   assert(watchedvar1 != -1 || watchedvar2 == -1);
332  	   assert(watchedvar1 == -1 || (0 <= watchedvar1 && watchedvar1 < consdata->nvars));
333  	   assert(watchedvar2 == -1 || (0 <= watchedvar2 && watchedvar2 < consdata->nvars));
334  	
335  	   /* if one watched variable is equal to the old other watched variable, just switch positions */
336  	   if( watchedvar1 == consdata->watchedvar2 || watchedvar2 == consdata->watchedvar1 )
337  	   {
338  	      int tmp;
339  	
340  	      tmp = consdata->watchedvar1;
341  	      consdata->watchedvar1 = consdata->watchedvar2;
342  	      consdata->watchedvar2 = tmp;
343  	      tmp = consdata->filterpos1;
344  	      consdata->filterpos1 = consdata->filterpos2;
345  	      consdata->filterpos2 = tmp;
346  	   }
347  	   assert(watchedvar1 == -1 || watchedvar1 != consdata->watchedvar2);
348  	   assert(watchedvar2 == -1 || watchedvar2 != consdata->watchedvar1);
349  	
350  	   /* drop events on old watched variables */
351  	   if( consdata->watchedvar1 != -1 && consdata->watchedvar1 != watchedvar1 )
352  	   {
353  	      assert(consdata->filterpos1 != -1);
354  	      SCIP_CALL( consdataDropWatchedEvents(scip, consdata, eventhdlr, consdata->watchedvar1, consdata->filterpos1) );
355  	   }
356  	   if( consdata->watchedvar2 != -1 && consdata->watchedvar2 != watchedvar2 )
357  	   {
358  	      assert(consdata->filterpos2 != -1);
359  	      SCIP_CALL( consdataDropWatchedEvents(scip, consdata, eventhdlr, consdata->watchedvar2, consdata->filterpos2) );
360  	   }
361  	
362  	   /* catch events on new watched variables */
363  	   if( watchedvar1 != -1 && watchedvar1 != consdata->watchedvar1 )
364  	   {
365  	      SCIP_CALL( consdataCatchWatchedEvents(scip, consdata, eventhdlr, watchedvar1, &consdata->filterpos1) );
366  	   }
367  	   if( watchedvar2 != -1 && watchedvar2 != consdata->watchedvar2 )
368  	   {
369  	      SCIP_CALL( consdataCatchWatchedEvents(scip, consdata, eventhdlr, watchedvar2, &consdata->filterpos2) );
370  	   }
371  	
372  	   /* set the new watched variables */
373  	   consdata->watchedvar1 = watchedvar1;
374  	   consdata->watchedvar2 = watchedvar2;
375  	
376  	   return SCIP_OKAY;
377  	}
378  	
379  	/** ensures, that the vars array can store at least num entries */
380  	static
381  	SCIP_RETCODE consdataEnsureVarsSize(
382  	   SCIP*                 scip,               /**< SCIP data structure */
383  	   SCIP_CONSDATA*        consdata,           /**< linear constraint data */
384  	   int                   num                 /**< minimum number of entries to store */
385  	   )
386  	{
387  	   assert(consdata != NULL);
388  	   assert(consdata->nvars <= consdata->varssize);
389  	
390  	   if( num > consdata->varssize )
391  	   {
392  	      int newsize;
393  	
394  	      newsize = SCIPcalcMemGrowSize(scip, num);
395  	      SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
396  	      consdata->varssize = newsize;
397  	   }
398  	   assert(num <= consdata->varssize);
399  	
400  	   return SCIP_OKAY;
401  	}
402  	
403  	/** creates constraint data for or constraint */
404  	static
405  	SCIP_RETCODE consdataCreate(
406  	   SCIP*                 scip,               /**< SCIP data structure */
407  	   SCIP_CONSDATA**       consdata,           /**< pointer to store the constraint data */
408  	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
409  	   int                   nvars,              /**< number of variables in the or operation */
410  	   SCIP_VAR**            vars,               /**< variables in or operation */
411  	   SCIP_VAR*             resvar              /**< resultant variable */
412  	   )
413  	{
414  	   assert(consdata != NULL);
415  	   assert(nvars == 0 || vars != NULL);
416  	   assert(resvar != NULL);
417  	
418  	   SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
419  	   SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
420  	   (*consdata)->resvar = resvar;
421  	   (*consdata)->rows = NULL;
422  	   (*consdata)->nvars = nvars;
423  	   (*consdata)->varssize = nvars;
424  	   (*consdata)->rowssize = 0;
425  	   (*consdata)->watchedvar1 = -1;
426  	   (*consdata)->watchedvar2 = -1;
427  	   (*consdata)->filterpos1 = -1;
428  	   (*consdata)->filterpos2 = -1;
429  	   (*consdata)->propagated = FALSE;
430  	   (*consdata)->nofixedone = FALSE;
431  	   (*consdata)->impladded = FALSE;
432  	   (*consdata)->opimpladded = FALSE;
433  	
434  	   /* get transformed variables, if we are in the transformed problem */
435  	   if( SCIPisTransformed(scip) )
436  	   {
437  	      SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
438  	      SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->resvar, &(*consdata)->resvar) );
439  	
440  	      /* catch needed events on variables */
441  	      SCIP_CALL( consdataCatchEvents(scip, *consdata, eventhdlr) );
442  	   }
443  	
444  	   return SCIP_OKAY;
445  	}
446  	
447  	/** releases LP rows of constraint data and frees rows array */
448  	static
449  	SCIP_RETCODE consdataFreeRows(
450  	   SCIP*                 scip,               /**< SCIP data structure */
451  	   SCIP_CONSDATA*        consdata            /**< constraint data */
452  	   )
453  	{
454  	   int r;
455  	
456  	   assert(consdata != NULL);
457  	
458  	   if( consdata->rows != NULL )
459  	   {
460  	      int nrows;
461  	
462  	      nrows = consdataGetNRows(consdata);
463  	
464  	      for( r = 0; r < nrows; ++r )
465  	      {
466  	         SCIP_CALL( SCIPreleaseRow(scip, &consdata->rows[r]) );
467  	      }
468  	      SCIPfreeBlockMemoryArray(scip, &consdata->rows, consdata->rowssize);
469  	   }
470  	
471  	   return SCIP_OKAY;
472  	}
473  	
474  	/** frees constraint data for or constraint */
475  	static
476  	SCIP_RETCODE consdataFree(
477  	   SCIP*                 scip,               /**< SCIP data structure */
478  	   SCIP_CONSDATA**       consdata,           /**< pointer to the constraint data */
479  	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
480  	   )
481  	{
482  	   assert(consdata != NULL);
483  	   assert(*consdata != NULL);
484  	
485  	   if( SCIPisTransformed(scip) )
486  	   {
487  	      /* drop events for watched variables */
488  	      SCIP_CALL( consdataSwitchWatchedvars(scip, *consdata, eventhdlr, -1, -1) );
489  	
490  	      /* drop all other events on variables */
491  	      SCIP_CALL( consdataDropEvents(scip, *consdata, eventhdlr) );
492  	   }
493  	   else
494  	   {
495  	      assert((*consdata)->watchedvar1 == -1);
496  	      assert((*consdata)->watchedvar2 == -1);
497  	   }
498  	
499  	   /* release and free the rows */
500  	   SCIP_CALL( consdataFreeRows(scip, *consdata) );
501  	
502  	   SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
503  	   SCIPfreeBlockMemory(scip, consdata);
504  	
505  	   return SCIP_OKAY;
506  	}
507  	
508  	/** prints or constraint to file stream */
509  	static
510  	SCIP_RETCODE consdataPrint(
511  	   SCIP*                 scip,               /**< SCIP data structure */
512  	   SCIP_CONSDATA*        consdata,           /**< or constraint data */
513  	   FILE*                 file                /**< output file (or NULL for standard output) */
514  	   )
515  	{
516  	   assert(consdata != NULL);
517  	
518  	   /* print resultant */
519  	   SCIP_CALL( SCIPwriteVarName(scip, file, consdata->resvar, TRUE) );
520  	
521  	   /* start the variable list */
522  	   SCIPinfoMessage(scip, file, " == or(");
523  	
524  	   /* print variable list */
525  	   SCIP_CALL( SCIPwriteVarsList(scip, file, consdata->vars, consdata->nvars, TRUE, ',') );
526  	
527  	   /* close the variable list */
528  	   SCIPinfoMessage(scip, file, ")");
529  	
530  	   return SCIP_OKAY;
531  	}
532  	
533  	/** adds coefficient in or constraint */
534  	static
535  	SCIP_RETCODE addCoef(
536  	   SCIP*                 scip,               /**< SCIP data structure */
537  	   SCIP_CONS*            cons,               /**< linear constraint */
538  	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
539  	   SCIP_VAR*             var                 /**< variable to add to the constraint */
540  	   )
541  	{
542  	   SCIP_CONSDATA* consdata;
543  	   SCIP_Bool transformed;
544  	
545  	   assert(var != NULL);
546  	
547  	   consdata = SCIPconsGetData(cons);
548  	   assert(consdata != NULL);
549  	   assert(consdata->rows == NULL);
550  	
551  	   /* are we in the transformed problem? */
552  	   transformed = SCIPconsIsTransformed(cons);
553  	
554  	   /* always use transformed variables in transformed constraints */
555  	   if( transformed )
556  	   {
557  	      SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
558  	   }
559  	   assert(var != NULL);
560  	   assert(transformed == SCIPvarIsTransformed(var));
561  	
562  	   SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
563  	   consdata->vars[consdata->nvars] = var;
564  	   consdata->nvars++;
565  	
566  	   /* if we are in transformed problem, catch the variable's events */
567  	   if( transformed )
568  	   {
569  	      /* catch bound change events of variable */
570  	      SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_LBTIGHTENED | SCIP_EVENTTYPE_UBRELAXED,
571  	            eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
572  	   }
573  	
574  	   /* install the rounding locks for the new variable */
575  	   SCIP_CALL( lockRounding(scip, cons, var) );
576  	
577  	   /**@todo update LP rows */
578  	   if( consdata->rows != NULL )
579  	   {
580  	      SCIPerrorMessage("cannot add coefficients to or constraint after LP relaxation was created\n");
581  	      return SCIP_INVALIDCALL;
582  	   }
583  	
584  	   return SCIP_OKAY;
585  	}
586  	
587  	/** deletes coefficient at given position from or constraint data */
588  	static
589  	SCIP_RETCODE delCoefPos(
590  	   SCIP*                 scip,               /**< SCIP data structure */
591  	   SCIP_CONS*            cons,               /**< or constraint */
592  	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
593  	   int                   pos                 /**< position of coefficient to delete */
594  	   )
595  	{
596  	   SCIP_CONSDATA* consdata;
597  	
598  	   assert(eventhdlr != NULL);
599  	
600  	   consdata = SCIPconsGetData(cons);
601  	   assert(consdata != NULL);
602  	   assert(0 <= pos && pos < consdata->nvars);
603  	   assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(consdata->vars[pos]));
604  	
605  	   /* remove the rounding locks of the variable */
606  	   SCIP_CALL( unlockRounding(scip, cons, consdata->vars[pos]) );
607  	
608  	   if( SCIPconsIsTransformed(cons) )
609  	   {
610  	      /* drop bound change events of variable */
611  	      SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], SCIP_EVENTTYPE_LBTIGHTENED | SCIP_EVENTTYPE_UBRELAXED,
612  	            eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
613  	   }
614  	
615  	   if( SCIPconsIsTransformed(cons) )
616  	   {
617  	      /* if the position is watched, stop watching the position */
618  	      if( consdata->watchedvar1 == pos )
619  	      {
620  	         SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar2, -1) );
621  	      }
622  	      if( consdata->watchedvar2 == pos )
623  	      {
624  	         SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar1, -1) );
625  	      }
626  	   }
627  	   assert(pos != consdata->watchedvar1);
628  	   assert(pos != consdata->watchedvar2);
629  	
630  	   /* move the last variable to the free slot */
631  	   consdata->vars[pos] = consdata->vars[consdata->nvars-1];
632  	   consdata->nvars--;
633  	
634  	   /* if the last variable (that moved) was watched, update the watched position */
635  	   if( consdata->watchedvar1 == consdata->nvars )
636  	      consdata->watchedvar1 = pos;
637  	   if( consdata->watchedvar2 == consdata->nvars )
638  	      consdata->watchedvar2 = pos;
639  	
640  	   consdata->propagated = FALSE;
641  	
642  	   return SCIP_OKAY;
643  	}
644  	
645  	/** deletes all zero-fixed variables */
646  	static
647  	SCIP_RETCODE applyFixings(
648  	   SCIP*                 scip,               /**< SCIP data structure */
649  	   SCIP_CONS*            cons,               /**< or constraint */
650  	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
651  	   )
652  	{
653  	   SCIP_CONSDATA* consdata;
654  	   SCIP_VAR* var;
655  	   int v;
656  	
657  	   consdata = SCIPconsGetData(cons);
658  	   assert(consdata != NULL);
659  	   assert(consdata->nvars == 0 || consdata->vars != NULL);
660  	
661  	   v = 0;
662  	   while( v < consdata->nvars )
663  	   {
664  	      var = consdata->vars[v];
665  	      assert(SCIPvarIsBinary(var));
666  	
667  	      if( SCIPvarGetUbGlobal(var) < 0.5 )
668  	      {
669  	         assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
670  	         SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
671  	      }
672  	      else
673  	      {
674  	         SCIP_VAR* repvar;
675  	         SCIP_Bool negated;
676  	
677  	         /* get binary representative of variable */
678  	         SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
679  	
680  	         /* check, if the variable should be replaced with the representative */
681  	         if( repvar != var )
682  	         {
683  	            /* delete old (aggregated) variable */
684  	            SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
685  	
686  	            /* add representative instead */
687  	            SCIP_CALL( addCoef(scip, cons, eventhdlr, repvar) );
688  	         }
689  	         else
690  	            ++v;
691  	      }
692  	   }
693  	
694  	   SCIPdebugMsg(scip, "after fixings: ");
695  	   SCIPdebug( SCIP_CALL(consdataPrint(scip, consdata, NULL)) );
696  	   SCIPdebugMsgPrint(scip, "\n");
697  	
698  	   return SCIP_OKAY;
699  	}
700  	
701  	/** creates LP rows corresponding to or constraint:
702  	 *   - for each operator variable vi:  resvar - vi            >= 0
703  	 *   - one additional row:             resvar - v1 - ... - vn <= 0
704  	 */
705  	static
706  	SCIP_RETCODE createRelaxation(
707  	   SCIP*                 scip,               /**< SCIP data structure */
708  	   SCIP_CONS*            cons                /**< constraint to check */
709  	   )
710  	{
711  	   SCIP_CONSDATA* consdata;
712  	   char rowname[SCIP_MAXSTRLEN];
713  	   int nvars;
714  	   int i;
715  	
716  	   consdata = SCIPconsGetData(cons);
717  	   assert(consdata != NULL);
718  	   assert(consdata->rows == NULL);
719  	
720  	   nvars = consdata->nvars;
721  	
722  	   /* get memory for rows */
723  	   consdata->rowssize = consdataGetNRows(consdata);
724  	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->rows, consdata->rowssize) );
725  	   assert(consdata->rowssize == nvars+1);
726  	
727  	   /* create operator rows */
728  	   for( i = 0; i < nvars; ++i )
729  	   {
730  	      (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), i);
731  	      SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[i], cons, rowname, 0.0, SCIPinfinity(scip),
732  	            SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) );
733  	      SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[i], consdata->resvar, 1.0) );
734  	      SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[i], consdata->vars[i], -1.0) );
735  	   }
736  	
737  	   /* create additional row */
738  	   (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_add", SCIPconsGetName(cons));
739  	   SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[nvars], cons, rowname, -SCIPinfinity(scip), 0.0,
740  	         SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) );
741  	   SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[nvars], consdata->resvar, 1.0) );
742  	   SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[nvars], nvars, consdata->vars, -1.0) );
743  	
744  	   return SCIP_OKAY;
745  	}
746  	
747  	/** adds linear relaxation of or constraint to the LP */
748  	static
749  	SCIP_RETCODE addRelaxation(
750  	   SCIP*                 scip,               /**< SCIP data structure */
751  	   SCIP_CONS*            cons,               /**< constraint to check */
752  	   SCIP_Bool*            infeasible          /**< pointer to store whether an infeasibility was detected */
753  	   )
754  	{
755  	   SCIP_CONSDATA* consdata;
756  	   int r;
757  	   int nrows;
758  	
759  	   consdata = SCIPconsGetData(cons);
760  	   assert(consdata != NULL);
761  	
762  	   if( consdata->rows == NULL )
763  	   {
764  	      SCIP_CALL( createRelaxation(scip, cons) );
765  	   }
766  	   assert( consdata->rows != NULL );
767  	
768  	   nrows = consdataGetNRows(consdata);
769  	
770  	   for( r = 0; r < nrows && !(*infeasible); ++r )
771  	   {
772  	      if( !SCIProwIsInLP(consdata->rows[r]) )
773  	      {
774  	         SCIP_CALL( SCIPaddRow(scip, consdata->rows[r], FALSE, infeasible) );
775  	      }
776  	   }
777  	
778  	   return SCIP_OKAY;
779  	}
780  	
781  	/** checks or constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
782  	static
783  	SCIP_RETCODE checkCons(
784  	   SCIP*                 scip,               /**< SCIP data structure */
785  	   SCIP_CONS*            cons,               /**< constraint to check */
786  	   SCIP_SOL*             sol,                /**< solution to check, NULL for current solution */
787  	   SCIP_Bool             checklprows,        /**< Do constraints represented by rows in the current LP have to be checked? */
788  	   SCIP_Bool             printreason,        /**< Should the reason for the violation be printed? */
789  	   SCIP_Bool*            violated            /**< pointer to store whether the constraint is violated */
790  	   )
791  	{
792  	   SCIP_CONSDATA* consdata;
793  	   SCIP_Bool mustcheck;
794  	   int r;
795  	
796  	   assert(violated != NULL);
797  	
798  	   consdata = SCIPconsGetData(cons);
799  	   assert(consdata != NULL);
800  	
801  	   *violated = FALSE;
802  	
803  	   /* check, if we can skip this feasibility check, because all rows are in the LP and doesn't have to be checked */
804  	   mustcheck = checklprows;
805  	   mustcheck = mustcheck || (consdata->rows == NULL);
806  	   if( !mustcheck )
807  	   {
808  	      int nrows;
809  	
810  	      assert(consdata->rows != NULL);
811  	
812  	      nrows = consdataGetNRows(consdata);
813  	
814  	      for( r = 0; r < nrows; ++r )
815  	      {
816  	         mustcheck = !SCIProwIsInLP(consdata->rows[r]);
817  	         if( mustcheck )
818  	            break;
819  	      }
820  	   }
821  	
822  	   /* check feasibility of constraint if necessary */
823  	   if( mustcheck )
824  	   {
825  	      SCIP_Real solval;
826  	      SCIP_Real maxsolval;
827  	      SCIP_Real sumsolval;
828  	      SCIP_Real viol;
829  	      int maxsolind;
830  	      int i;
831  	
832  	      /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
833  	       * enforcement
834  	       */
835  	      if( sol == NULL )
836  	      {
837  	         SCIP_CALL( SCIPincConsAge(scip, cons) );
838  	      }
839  	
840  	      maxsolind = 0;
841  	      maxsolval = 0.0;
842  	      sumsolval = 0.0;
843  	
844  	      /* evaluate operator variables */
845  	      for( i = 0; i < consdata->nvars; ++i )
846  	      {
847  	         solval = SCIPgetSolVal(scip, sol, consdata->vars[i]);
848  	
849  	         if( solval > maxsolval )
850  	         {
851  	            maxsolind = i;
852  	            maxsolval = solval;
853  	         }
854  	
855  	         sumsolval += solval;
856  	      }
857  	
858  	      /* the resultant must be at least as large as every operator
859  	       * and at most as large as the sum of operators
860  	       */
861  	      solval = SCIPgetSolVal(scip, sol, consdata->resvar);
862  	      viol = MAX3(0.0, maxsolval - solval, solval - sumsolval);
863  	
864  	      if( SCIPisFeasPositive(scip, viol) )
865  	      {
866  	         *violated = TRUE;
867  	
868  	         /* only reset constraint age if we are in enforcement */
869  	         if( sol == NULL )
870  	         {
871  	            SCIP_CALL( SCIPresetConsAge(scip, cons) );
872  	         }
873  	
874  	         if( printreason )
875  	         {
876  	            SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
877  	            SCIPinfoMessage(scip, NULL, ";\n");
878  	            SCIPinfoMessage(scip, NULL, "violation:");
879  	
880  	            if( SCIPisFeasPositive(scip, maxsolval - solval) )
881  	            {
882  	               SCIPinfoMessage(scip, NULL, " operand <%s> = TRUE and resultant <%s> = FALSE\n",
883  	                  SCIPvarGetName(consdata->vars[maxsolind]), SCIPvarGetName(consdata->resvar));
884  	            }
885  	            else
886  	            {
887  	               SCIPinfoMessage(scip, NULL, " all operands are FALSE and resultant <%s> = TRUE\n",
888  	                  SCIPvarGetName(consdata->resvar));
889  	            }
890  	         }
891  	      }
892  	
893  	      if( sol != NULL )
894  	         SCIPupdateSolConsViolation(scip, sol, viol, viol);
895  	   }
896  	
897  	   return SCIP_OKAY;
898  	}
899  	
900  	/** separates current LP solution */
901  	static
902  	SCIP_RETCODE separateCons(
903  	   SCIP*                 scip,               /**< SCIP data structure */
904  	   SCIP_CONS*            cons,               /**< constraint to check */
905  	   SCIP_SOL*             sol,                /**< primal CIP solution, NULL for current LP solution */
906  	   SCIP_Bool*            separated           /**< pointer to store whether a cut was found */
907  	   )
908  	{
909  	   SCIP_CONSDATA* consdata;
910  	   SCIP_Real feasibility;
911  	   int r;
912  	   int nrows;
913  	
914  	   assert(separated != NULL);
915  	
916  	   consdata = SCIPconsGetData(cons);
917  	   assert(consdata != NULL);
918  	
919  	   *separated = FALSE;
920  	
921  	   /* create all necessary rows for the linear relaxation */
922  	   if( consdata->rows == NULL )
923  	   {
924  	      SCIP_CALL( createRelaxation(scip, cons) );
925  	   }
926  	   assert(consdata->rows != NULL);
927  	
928  	   nrows = consdataGetNRows(consdata);
929  	
930  	   /* test all rows for feasibility and add infeasible rows */
931  	   for( r = 0; r < nrows; ++r )
932  	   {
933  	      if( !SCIProwIsInLP(consdata->rows[r]) )
934  	      {
935  	         feasibility = SCIPgetRowSolFeasibility(scip, consdata->rows[r], sol);
936  	         if( SCIPisFeasNegative(scip, feasibility) )
937  	         {
938  	            SCIP_Bool infeasible;
939  	
940  	            SCIP_CALL( SCIPaddRow(scip, consdata->rows[r], FALSE, &infeasible) );
941  	            assert( ! infeasible );
942  	            *separated = TRUE;
943  	         }
944  	      }
945  	   }
946  	
947  	   return SCIP_OKAY;
948  	}
949  	
950  	/** analyzes conflicting FALSE assignment to resultant of given constraint, and adds conflict constraint to problem */
951  	static
952  	SCIP_RETCODE analyzeConflictZero(
953  	   SCIP*                 scip,               /**< SCIP data structure */
954  	   SCIP_CONS*            cons,               /**< or constraint that detected the conflict */
955  	   int                   truepos             /**< position of operand that is fixed to TRUE */
956  	   )
957  	{
958  	   SCIP_CONSDATA* consdata;
959  	
960  	   /* conflict analysis can only be applied in solving stage and if it is applicable */
961  	   if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
962  	      return SCIP_OKAY;
963  	
964  	   consdata = SCIPconsGetData(cons);
965  	   assert(consdata != NULL);
966  	   assert(SCIPvarGetUbLocal(consdata->resvar) < 0.5);
967  	   assert(0 <= truepos && truepos < consdata->nvars);
968  	   assert(SCIPvarGetLbLocal(consdata->vars[truepos]) > 0.5);
969  	
970  	   /* initialize conflict analysis, and add resultant and single operand variable to conflict candidate queue */
971  	   SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
972  	
973  	   SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
974  	   SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[truepos]) );
975  	
976  	   /* analyze the conflict */
977  	   SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
978  	
979  	   return SCIP_OKAY;
980  	}
981  	
982  	/** analyzes conflicting TRUE assignment to resultant of given constraint, and adds conflict constraint to problem */
983  	static
984  	SCIP_RETCODE analyzeConflictOne(
985  	   SCIP*                 scip,               /**< SCIP data structure */
986  	   SCIP_CONS*            cons                /**< or constraint that detected the conflict */
987  	   )
988  	{
989  	   SCIP_CONSDATA* consdata;
990  	   int v;
991  	
992  	   assert(!SCIPconsIsModifiable(cons));
993  	
994  	   /* conflict analysis can only be applied in solving stage and if it is applicable */
995  	   if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
996  	      return SCIP_OKAY;
997  	
998  	   consdata = SCIPconsGetData(cons);
999  	   assert(consdata != NULL);
1000 	   assert(SCIPvarGetLbLocal(consdata->resvar) > 0.5);
1001 	
1002 	   /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1003 	   SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
1004 	
1005 	   SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
1006 	   for( v = 0; v < consdata->nvars; ++v )
1007 	   {
1008 	      assert(SCIPvarGetUbLocal(consdata->vars[v]) < 0.5);
1009 	      SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
1010 	   }
1011 	
1012 	   /* analyze the conflict */
1013 	   SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1014 	
1015 	   return SCIP_OKAY;
1016 	}
1017 	
1018 	/** propagates constraint with the following rules:
1019 	 *   (1) v_i = TRUE                                   =>  r   = TRUE
1020 	 *   (2) r   = FALSE                                  =>  v_i = FALSE for all i
1021 	 *   (3) v_i = FALSE for all i                        =>  r   = FALSE
1022 	 *   (4) r   = TRUE, v_i = FALSE for all i except j   =>  v_j = TRUE
1023 	 */
1024 	static
1025 	SCIP_RETCODE propagateCons(
1026 	   SCIP*                 scip,               /**< SCIP data structure */
1027 	   SCIP_CONS*            cons,               /**< or constraint to be processed */
1028 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
1029 	   SCIP_Bool*            cutoff,             /**< pointer to store TRUE, if the node can be cut off */
1030 	   int*                  nfixedvars          /**< pointer to add up the number of found domain reductions */
1031 	   )
1032 	{
1033 	   SCIP_CONSDATA* consdata;
1034 	   SCIP_VAR* resvar;
1035 	   SCIP_VAR** vars;
1036 	   int nvars;
1037 	   int watchedvar1;
1038 	   int watchedvar2;
1039 	   int i;
1040 	   SCIP_Bool infeasible;
1041 	   SCIP_Bool tightened;
1042 	
1043 	   assert(cutoff != NULL);
1044 	   assert(nfixedvars != NULL);
1045 	
1046 	   consdata = SCIPconsGetData(cons);
1047 	   assert(consdata != NULL);
1048 	
1049 	   resvar = consdata->resvar;
1050 	   vars = consdata->vars;
1051 	   nvars = consdata->nvars;
1052 	
1053 	   /* don't process the constraint, if none of the operator variables was fixed to TRUE, and if the watched variables
1054 	    * and the resultant weren't fixed to any value since last propagation call
1055 	    */
1056 	   if( consdata->propagated )
1057 	   {
1058 	      assert(consdata->nofixedone);
1059 	      assert(SCIPisFeasEQ(scip, SCIPvarGetUbLocal(resvar), 1.0));
1060 	      return SCIP_OKAY;
1061 	   }
1062 	
1063 	   /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
1064 	   if( !SCIPinRepropagation(scip) )
1065 	   {
1066 	      SCIP_CALL( SCIPincConsAge(scip, cons) );
1067 	   }
1068 	
1069 	   /* if one of the operator variables was fixed to TRUE, the resultant can be fixed to TRUE (rule (1)) */
1070 	   if( !consdata->nofixedone )
1071 	   {
1072 	      for( i = 0; i < nvars && SCIPvarGetLbLocal(vars[i]) < 0.5; ++i ) /* search fixed operator */
1073 	      {}
1074 	      if( i < nvars )
1075 	      {
1076 	         SCIPdebugMsg(scip, "constraint <%s>: operator var <%s> fixed to 1.0 -> fix resultant <%s> to 1.0\n",
1077 	            SCIPconsGetName(cons), SCIPvarGetName(vars[i]), SCIPvarGetName(resvar));
1078 	         SCIP_CALL( SCIPinferBinvarCons(scip, resvar, TRUE, cons, (int)PROPRULE_1, &infeasible, &tightened) );
1079 	         if( infeasible )
1080 	         {
1081 	            /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1082 	            SCIP_CALL( analyzeConflictZero(scip, cons, i) );
1083 	            SCIP_CALL( SCIPresetConsAge(scip, cons) );
1084 	            *cutoff = TRUE;
1085 	         }
1086 	         else
1087 	         {
1088 	            SCIP_CALL( SCIPdelConsLocal(scip, cons) );
1089 	            if( tightened )
1090 	            {
1091 	               SCIP_CALL( SCIPresetConsAge(scip, cons) );
1092 	               (*nfixedvars)++;
1093 	            }
1094 	         }
1095 	
1096 	         return SCIP_OKAY;
1097 	      }
1098 	      else
1099 	         consdata->nofixedone = TRUE;
1100 	   }
1101 	   assert(consdata->nofixedone);
1102 	
1103 	   /* if resultant is fixed to FALSE, all operator variables can be fixed to FALSE (rule (2)) */
1104 	   if( SCIPvarGetUbLocal(resvar) < 0.5 )
1105 	   {
1106 	      for( i = 0; i < nvars && !(*cutoff); ++i )
1107 	      {
1108 	         SCIPdebugMsg(scip, "constraint <%s>: resultant var <%s> fixed to 0.0 -> fix operator var <%s> to 0.0\n",
1109 	            SCIPconsGetName(cons), SCIPvarGetName(resvar), SCIPvarGetName(vars[i]));
1110 	         SCIP_CALL( SCIPinferBinvarCons(scip, vars[i], FALSE, cons, (int)PROPRULE_2, &infeasible, &tightened) );
1111 	         if( infeasible )
1112 	         {
1113 	            /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1114 	            SCIP_CALL( analyzeConflictZero(scip, cons, i) );
1115 	            SCIP_CALL( SCIPresetConsAge(scip, cons) );
1116 	            *cutoff = TRUE;
1117 	         }
1118 	         else if( tightened )
1119 	         {
1120 	            SCIP_CALL( SCIPresetConsAge(scip, cons) );
1121 	            (*nfixedvars)++;
1122 	         }
1123 	      }
1124 	
1125 	      if( !(*cutoff) )
1126 	      {
1127 	         SCIP_CALL( SCIPdelConsLocal(scip, cons) );
1128 	      }
1129 	
1130 	      return SCIP_OKAY;
1131 	   }
1132 	
1133 	   /* rules (3) and (4) can only be applied, if we know all operator variables */
1134 	   if( SCIPconsIsModifiable(cons) )
1135 	      return SCIP_OKAY;
1136 	
1137 	   /* rules (3) and (4) cannot be applied, if we have at least two unfixed variables left;
1138 	    * that means, we only have to watch (i.e. capture events) of two variables, and switch to other variables
1139 	    * if these ones get fixed
1140 	    */
1141 	   watchedvar1 = consdata->watchedvar1;
1142 	   watchedvar2 = consdata->watchedvar2;
1143 	
1144 	   /* check, if watched variables are still unfixed */
1145 	   if( watchedvar1 != -1 )
1146 	   {
1147 	      assert(SCIPvarGetLbLocal(vars[watchedvar1]) < 0.5); /* otherwise, rule (1) could be applied */
1148 	      if( SCIPvarGetUbLocal(vars[watchedvar1]) < 0.5 )
1149 	         watchedvar1 = -1;
1150 	   }
1151 	   if( watchedvar2 != -1 )
1152 	   {
1153 	      assert(SCIPvarGetLbLocal(vars[watchedvar2]) < 0.5); /* otherwise, rule (1) could be applied */
1154 	      if( SCIPvarGetUbLocal(vars[watchedvar2]) < 0.5 )
1155 	         watchedvar2 = -1;
1156 	   }
1157 	
1158 	   /* if only one watched variable is still unfixed, make it the first one */
1159 	   if( watchedvar1 == -1 )
1160 	   {
1161 	      watchedvar1 = watchedvar2;
1162 	      watchedvar2 = -1;
1163 	   }
1164 	   assert(watchedvar1 != -1 || watchedvar2 == -1);
1165 	
1166 	   /* if the watched variables are invalid (fixed), find new ones if existing */
1167 	   if( watchedvar2 == -1 )
1168 	   {
1169 	      for( i = 0; i < nvars; ++i )
1170 	      {
1171 	         assert(SCIPvarGetLbLocal(vars[i]) < 0.5); /* otherwise, rule (1) could be applied */
1172 	         if( SCIPvarGetUbLocal(vars[i]) > 0.5 )
1173 	         {
1174 	            if( watchedvar1 == -1 )
1175 	            {
1176 	               assert(watchedvar2 == -1);
1177 	               watchedvar1 = i;
1178 	            }
1179 	            else if( watchedvar1 != i )
1180 	            {
1181 	               watchedvar2 = i;
1182 	               break;
1183 	            }
1184 	         }
1185 	      }
1186 	   }
1187 	   assert(watchedvar1 != -1 || watchedvar2 == -1);
1188 	
1189 	   /* if all variables are fixed to FALSE, the resultant can also be fixed to FALSE (rule (3)) */
1190 	   if( watchedvar1 == -1 )
1191 	   {
1192 	      assert(watchedvar2 == -1);
1193 	
1194 	      SCIPdebugMsg(scip, "constraint <%s>: all operator vars fixed to 0.0 -> fix resultant <%s> to 0.0\n",
1195 	         SCIPconsGetName(cons), SCIPvarGetName(resvar));
1196 	      SCIP_CALL( SCIPinferBinvarCons(scip, resvar, FALSE, cons, (int)PROPRULE_3, &infeasible, &tightened) );
1197 	      if( infeasible )
1198 	      {
1199 	         /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1200 	         SCIP_CALL( analyzeConflictOne(scip, cons) );
1201 	         SCIP_CALL( SCIPresetConsAge(scip, cons) );
1202 	         *cutoff = TRUE;
1203 	      }
1204 	      else
1205 	      {
1206 	         SCIP_CALL( SCIPdelConsLocal(scip, cons) );
1207 	         if( tightened )
1208 	         {
1209 	            SCIP_CALL( SCIPresetConsAge(scip, cons) );
1210 	            (*nfixedvars)++;
1211 	         }
1212 	      }
1213 	
1214 	      return SCIP_OKAY;
1215 	   }
1216 	
1217 	   /* if resultant is fixed to TRUE, and only one operator variable is not fixed to FALSE, this operator variable
1218 	    * can be fixed to TRUE (rule (4))
1219 	    */
1220 	   if( SCIPvarGetLbLocal(resvar) > 0.5 && watchedvar2 == -1 )
1221 	   {
1222 	      assert(watchedvar1 != -1);
1223 	
1224 	      SCIPdebugMsg(scip, "constraint <%s>: resultant <%s> fixed to 1.0, only one unfixed operand -> fix operand <%s> to 1.0\n",
1225 	         SCIPconsGetName(cons), SCIPvarGetName(resvar), SCIPvarGetName(vars[watchedvar1]));
1226 	      SCIP_CALL( SCIPinferBinvarCons(scip, vars[watchedvar1], TRUE, cons, (int)PROPRULE_4, &infeasible, &tightened) );
1227 	      if( infeasible )
1228 	      {
1229 	         /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1230 	         SCIP_CALL( analyzeConflictOne(scip, cons) );
1231 	         SCIP_CALL( SCIPresetConsAge(scip, cons) );
1232 	         *cutoff = TRUE;
1233 	      }
1234 	      else
1235 	      {
1236 	         SCIP_CALL( SCIPdelConsLocal(scip, cons) );
1237 	         if( tightened )
1238 	         {
1239 	            SCIP_CALL( SCIPresetConsAge(scip, cons) );
1240 	            (*nfixedvars)++;
1241 	         }
1242 	      }
1243 	
1244 	      return SCIP_OKAY;
1245 	   }
1246 	
1247 	   /* switch to the new watched variables */
1248 	   SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, watchedvar1, watchedvar2) );
1249 	
1250 	   /* mark the constraint propagated */
1251 	   consdata->propagated = TRUE;
1252 	
1253 	   return SCIP_OKAY;
1254 	}
1255 	
1256 	/** resolves a conflict on the given variable by supplying the variables needed for applying the corresponding
1257 	 *  propagation rule (see propagateCons()):
1258 	 *   (1) v_i = TRUE                                   =>  r   = TRUE
1259 	 *   (2) r   = FALSE                                  =>  v_i = FALSE for all i
1260 	 *   (3) v_i = FALSE for all i                        =>  r   = FALSE
1261 	 *   (4) r   = TRUE, v_i = FALSE for all i except j   =>  v_j = TRUE
1262 	 */
1263 	static
1264 	SCIP_RETCODE resolvePropagation(
1265 	   SCIP*                 scip,               /**< SCIP data structure */
1266 	   SCIP_CONS*            cons,               /**< constraint that inferred the bound change */
1267 	   SCIP_VAR*             infervar,           /**< variable that was deduced */
1268 	   PROPRULE              proprule,           /**< propagation rule that deduced the value */
1269 	   SCIP_BDCHGIDX*        bdchgidx,           /**< bound change index (time stamp of bound change), or NULL for current time */
1270 	   SCIP_RESULT*          result              /**< pointer to store the result of the propagation conflict resolving call */
1271 	   )
1272 	{
1273 	   SCIP_CONSDATA* consdata;
1274 	   SCIP_VAR** vars;
1275 	   int nvars;
1276 	   int i;
1277 	
1278 	   assert(result != NULL);
1279 	
1280 	   consdata = SCIPconsGetData(cons);
1281 	   assert(consdata != NULL);
1282 	   vars = consdata->vars;
1283 	   nvars = consdata->nvars;
1284 	
1285 	   switch( proprule )
1286 	   {
1287 	   case PROPRULE_1:
1288 	      /* the resultant was inferred to TRUE, because one operand variable was TRUE */
1289 	      assert(SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5);
1290 	      assert(infervar == consdata->resvar);
1291 	      for( i = 0; i < nvars; ++i )
1292 	      {
1293 	         if( SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) > 0.5 )
1294 	         {
1295 	            SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
1296 	            break;
1297 	         }
1298 	      }
1299 	      assert(i < nvars);
1300 	      *result = SCIP_SUCCESS;
1301 	      break;
1302 	
1303 	   case PROPRULE_2:
1304 	      /* the operand variable was inferred to FALSE, because the resultant was FALSE */
1305 	      assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < 0.5);
1306 	      assert(SCIPgetVarUbAtIndex(scip, consdata->resvar, bdchgidx, FALSE) < 0.5);
1307 	      SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
1308 	      *result = SCIP_SUCCESS;
1309 	      break;
1310 	
1311 	   case PROPRULE_3:
1312 	      /* the resultant was inferred to FALSE, because all operand variables were FALSE */
1313 	      assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < 0.5);
1314 	      assert(infervar == consdata->resvar);
1315 	      for( i = 0; i < nvars; ++i )
1316 	      {
1317 	         assert(SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) < 0.5);
1318 	         SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
1319 	      }
1320 	      *result = SCIP_SUCCESS;
1321 	      break;
1322 	
1323 	   case PROPRULE_4:
1324 	      /* the operand variable was inferred to TRUE, because the resultant was TRUE and all other operands were FALSE */
1325 	      assert(SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5);
1326 	      assert(SCIPgetVarLbAtIndex(scip, consdata->resvar, bdchgidx, FALSE) > 0.5);
1327 	      SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
1328 	      for( i = 0; i < nvars; ++i )
1329 	      {
1330 	         if( vars[i] != infervar )
1331 	         {
1332 	            assert(SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) < 0.5);
1333 	            SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
1334 	         }
1335 	      }
1336 	      *result = SCIP_SUCCESS;
1337 	      break;
1338 	
1339 	   case PROPRULE_INVALID:
1340 	   default:
1341 	      SCIPerrorMessage("invalid inference information %d in or constraint <%s>\n", proprule, SCIPconsGetName(cons));
1342 	      return SCIP_INVALIDDATA;
1343 	   }
1344 	
1345 	   return SCIP_OKAY;
1346 	}
1347 	
1348 	/** upgrades unmodifiable or constraint into an and constraint on negated variables */
1349 	static
1350 	SCIP_RETCODE upgradeCons(
1351 	   SCIP*                 scip,               /**< SCIP data structure */
1352 	   SCIP_CONS*            cons,               /**< constraint that inferred the bound change */
1353 	   int*                  nupgdconss          /**< pointer to count the number of constraint upgrades */
1354 	   )
1355 	{
1356 	   SCIP_CONSDATA* consdata;
1357 	   SCIP_VAR** negvars;
1358 	   SCIP_VAR* negresvar;
1359 	   SCIP_CONS* andcons;
1360 	   int i;
1361 	
1362 	   assert(nupgdconss != NULL);
1363 	
1364 	   /* we cannot upgrade a modifiable constraint, since we don't know what additional variables to expect */
1365 	   if( SCIPconsIsModifiable(cons) )
1366 	      return SCIP_OKAY;
1367 	
1368 	   SCIPdebugMsg(scip, "upgrading or constraint <%s> into equivalent and constraint on negated variables\n",
1369 	      SCIPconsGetName(cons));
1370 	
1371 	   consdata = SCIPconsGetData(cons);
1372 	   assert(consdata != NULL);
1373 	
1374 	   /* get the negated versions of the variables */
1375 	   SCIP_CALL( SCIPallocBufferArray(scip, &negvars, consdata->nvars) );
1376 	   for( i = 0; i < consdata->nvars; ++i )
1377 	   {
1378 	      SCIP_CALL( SCIPgetNegatedVar(scip, consdata->vars[i], &negvars[i]) );
1379 	   }
1380 	   SCIP_CALL( SCIPgetNegatedVar(scip, consdata->resvar, &negresvar) );
1381 	
1382 	   /* create and add the and constraint */
1383 	   SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, SCIPconsGetName(cons), negresvar, consdata->nvars, negvars,
1384 	         SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
1385 	         SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
1386 	         SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
1387 	   SCIP_CALL( SCIPaddCons(scip, andcons) );
1388 	   SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
1389 	
1390 	   /* delete the or constraint */
1391 	   SCIP_CALL( SCIPdelCons(scip, cons) );
1392 	
1393 	   /* free temporary memory */
1394 	   SCIPfreeBufferArray(scip, &negvars);
1395 	
1396 	   (*nupgdconss)++;
1397 	
1398 	   return SCIP_OKAY;
1399 	}
1400 	
1401 	/** adds symmetry information of constraint to a symmetry detection graph */
1402 	static
1403 	SCIP_RETCODE addSymmetryInformation(
1404 	   SCIP*                 scip,               /**< SCIP pointer */
1405 	   SYM_SYMTYPE           symtype,            /**< type of symmetries that need to be added */
1406 	   SCIP_CONS*            cons,               /**< constraint */
1407 	   SYM_GRAPH*            graph,              /**< symmetry detection graph */
1408 	   SCIP_Bool*            success             /**< pointer to store whether symmetry information could be added */
1409 	   )
1410 	{
1411 	   SCIP_CONSDATA* consdata;
1412 	   SCIP_VAR** orvars;
1413 	   SCIP_VAR** vars;
1414 	   SCIP_Real* vals;
1415 	   SCIP_Real constant = 0.0;
1416 	   int nlocvars;
1417 	   int nvars;
1418 	   int i;
1419 	
1420 	   assert(scip != NULL);
1421 	   assert(cons != NULL);
1422 	   assert(graph != NULL);
1423 	   assert(success != NULL);
1424 	
1425 	   consdata = SCIPconsGetData(cons);
1426 	   assert(consdata != NULL);
1427 	
1428 	   /* get active variables of the constraint */
1429 	   nvars = SCIPgetNVars(scip);
1430 	   nlocvars = SCIPgetNVarsOr(scip, cons);
1431 	
1432 	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1433 	   SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
1434 	
1435 	   orvars = SCIPgetVarsOr(scip, cons);
1436 	   for( i = 0; i < consdata->nvars; ++i )
1437 	   {
1438 	      vars[i] = orvars[i];
1439 	      vals[i] = 1.0;
1440 	   }
1441 	
1442 	   assert(SCIPgetResultantOr(scip, cons) != NULL);
1443 	   vars[nlocvars] = SCIPgetResultantOr(scip, cons);
1444 	   vals[nlocvars++] = 2.0;
1445 	   assert(nlocvars <= nvars);
1446 	
1447 	   SCIP_CALL( SCIPgetActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
1448 	
1449 	   /* represent the OR constraint via the gadget for linear constraints and use the constant as lhs/rhs to
1450 	    * distinguish different OR constraints (OR constraints do not have an intrinsic right-hand side)
1451 	    */
1452 	   SCIP_CALL( SCIPextendPermsymDetectionGraphLinear(scip, graph, vars, vals, nlocvars,
1453 	         cons, -constant, -constant, success) );
1454 	
1455 	   SCIPfreeBufferArray(scip, &vals);
1456 	   SCIPfreeBufferArray(scip, &vars);
1457 	
1458 	   return SCIP_OKAY;
1459 	}
1460 	
1461 	/*
1462 	 * Callback methods of constraint handler
1463 	 */
1464 	
1465 	/** copy method for constraint handler plugins (called when SCIP copies plugins) */
1466 	static
1467 	SCIP_DECL_CONSHDLRCOPY(conshdlrCopyOr)
1468 	{  /*lint --e{715}*/
1469 	   assert(scip != NULL);
1470 	   assert(conshdlr != NULL);
1471 	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1472 	
1473 	   /* call inclusion method of constraint handler */
1474 	   SCIP_CALL( SCIPincludeConshdlrOr(scip) );
1475 	
1476 	   *valid = TRUE;
1477 	
1478 	   return SCIP_OKAY;
1479 	}
1480 	
1481 	/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
1482 	static
1483 	SCIP_DECL_CONSFREE(consFreeOr)
1484 	{  /*lint --e{715}*/
1485 	   SCIP_CONSHDLRDATA* conshdlrdata;
1486 	
1487 	   /* free constraint handler data */
1488 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1489 	   assert(conshdlrdata != NULL);
1490 	
1491 	   conshdlrdataFree(scip, &conshdlrdata);
1492 	
1493 	   SCIPconshdlrSetData(conshdlr, NULL);
1494 	
1495 	   return SCIP_OKAY;
1496 	}
1497 	
1498 	
1499 	/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
1500 	static
1501 	SCIP_DECL_CONSEXITSOL(consExitsolOr)
1502 	{  /*lint --e{715}*/
1503 	   SCIP_CONSDATA* consdata;
1504 	   int c;
1505 	
1506 	   /* release and free the rows of all constraints */
1507 	   for( c = 0; c < nconss; ++c )
1508 	   {
1509 	      consdata = SCIPconsGetData(conss[c]);
1510 	      SCIP_CALL( consdataFreeRows(scip, consdata) );
1511 	   }
1512 	
1513 	   return SCIP_OKAY;
1514 	}
1515 	
1516 	
1517 	/** frees specific constraint data */
1518 	static
1519 	SCIP_DECL_CONSDELETE(consDeleteOr)
1520 	{  /*lint --e{715}*/
1521 	   SCIP_CONSHDLRDATA* conshdlrdata;
1522 	
1523 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1524 	   assert(conshdlrdata != NULL);
1525 	
1526 	   SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
1527 	
1528 	   return SCIP_OKAY;
1529 	}
1530 	
1531 	
1532 	/** transforms constraint data into data belonging to the transformed problem */
1533 	static
1534 	SCIP_DECL_CONSTRANS(consTransOr)
1535 	{  /*lint --e{715}*/
1536 	   SCIP_CONSHDLRDATA* conshdlrdata;
1537 	   SCIP_CONSDATA* sourcedata;
1538 	   SCIP_CONSDATA* targetdata;
1539 	
1540 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1541 	   assert(conshdlrdata != NULL);
1542 	
1543 	   sourcedata = SCIPconsGetData(sourcecons);
1544 	   assert(sourcedata != NULL);
1545 	
1546 	   /* create target constraint data */
1547 	   SCIP_CALL( consdataCreate(scip, &targetdata, conshdlrdata->eventhdlr,
1548 	         sourcedata->nvars, sourcedata->vars, sourcedata->resvar) );
1549 	
1550 	   /* create target constraint */
1551 	   SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
1552 	         SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
1553 	         SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
1554 	         SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
1555 	         SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
1556 	
1557 	   return SCIP_OKAY;
1558 	}
1559 	
1560 	
1561 	/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
1562 	static
1563 	SCIP_DECL_CONSINITLP(consInitlpOr)
1564 	{  /*lint --e{715}*/
1565 	   int i;
1566 	
1567 	   *infeasible = FALSE;
1568 	
1569 	   for( i = 0; i < nconss && !(*infeasible); i++ )
1570 	   {
1571 	      assert(SCIPconsIsInitial(conss[i]));
1572 	      SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
1573 	   }
1574 	
1575 	   return SCIP_OKAY;
1576 	}
1577 	
1578 	
1579 	/** separation method of constraint handler for LP solutions */
1580 	static
1581 	SCIP_DECL_CONSSEPALP(consSepalpOr)
1582 	{  /*lint --e{715}*/
1583 	   SCIP_Bool separated;
1584 	   int c;
1585 	
1586 	   *result = SCIP_DIDNOTFIND;
1587 	
1588 	   /* separate all useful constraints */
1589 	   for( c = 0; c < nusefulconss; ++c )
1590 	   {
1591 	      SCIP_CALL( separateCons(scip, conss[c], NULL, &separated) );
1592 	      if( separated )
1593 	         *result = SCIP_SEPARATED;
1594 	   }
1595 	
1596 	   /* combine constraints to get more cuts */
1597 	   /**@todo combine constraints to get further cuts */
1598 	
1599 	   return SCIP_OKAY;
1600 	}
1601 	
1602 	
1603 	/** separation method of constraint handler for arbitrary primal solutions */
1604 	static
1605 	SCIP_DECL_CONSSEPASOL(consSepasolOr)
1606 	{  /*lint --e{715}*/
1607 	   SCIP_Bool separated;
1608 	   int c;
1609 	
1610 	   *result = SCIP_DIDNOTFIND;
1611 	
1612 	   /* separate all useful constraints */
1613 	   for( c = 0; c < nusefulconss; ++c )
1614 	   {
1615 	      SCIP_CALL( separateCons(scip, conss[c], sol, &separated) );
1616 	      if( separated )
1617 	         *result = SCIP_SEPARATED;
1618 	   }
1619 	
1620 	   /* combine constraints to get more cuts */
1621 	   /**@todo combine constraints to get further cuts */
1622 	
1623 	   return SCIP_OKAY;
1624 	}
1625 	
1626 	
1627 	/** constraint enforcing method of constraint handler for LP solutions */
1628 	static
1629 	SCIP_DECL_CONSENFOLP(consEnfolpOr)
1630 	{  /*lint --e{715}*/
1631 	   SCIP_Bool violated;
1632 	   int i;
1633 	
1634 	   /* method is called only for integral solutions, because the enforcing priority is negative */
1635 	   for( i = 0; i < nconss; i++ )
1636 	   {
1637 	      SCIP_CALL( checkCons(scip, conss[i], NULL, FALSE, FALSE, &violated) );
1638 	      if( violated )
1639 	      {
1640 	         SCIP_Bool separated;
1641 	
1642 	         SCIP_CALL( separateCons(scip, conss[i], NULL, &separated) );
1643 	
1644 	         /* if the solution is integral, the separation always finds a cut
1645 	          * if some implicit binary variable is not integral, then some other constraint needs to be enforced first
1646 	          */
1647 	         if( separated )
1648 	            *result = SCIP_SEPARATED;
1649 	         else
1650 	            *result = SCIP_INFEASIBLE;
1651 	
1652 	         return SCIP_OKAY;
1653 	      }
1654 	   }
1655 	   *result = SCIP_FEASIBLE;
1656 	
1657 	   return SCIP_OKAY;
1658 	}
1659 	
1660 	
1661 	/** constraint enforcing method of constraint handler for relaxation solutions */
1662 	static
1663 	SCIP_DECL_CONSENFORELAX(consEnforelaxOr)
1664 	{  /*lint --e{715}*/
1665 	   SCIP_Bool violated;
1666 	   int i;
1667 	
1668 	   /* method is called only for integral solutions, because the enforcing priority is negative */
1669 	   for( i = 0; i < nconss; i++ )
1670 	   {
1671 	      SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
1672 	      if( violated )
1673 	      {
1674 	         SCIP_Bool separated;
1675 	
1676 	         SCIP_CALL( separateCons(scip, conss[i], sol, &separated) );
1677 	
1678 	         /* if the solution is integral, the separation always finds a cut
1679 	          * if some implicit binary variable is not integral, then some other constraint needs to be enforced first
1680 	          */
1681 	         if( separated )
1682 	            *result = SCIP_SEPARATED;
1683 	         else
1684 	            *result = SCIP_INFEASIBLE;
1685 	
1686 	         return SCIP_OKAY;
1687 	      }
1688 	   }
1689 	   *result = SCIP_FEASIBLE;
1690 	
1691 	   return SCIP_OKAY;
1692 	}
1693 	
1694 	
1695 	/** constraint enforcing method of constraint handler for pseudo solutions */
1696 	static
1697 	SCIP_DECL_CONSENFOPS(consEnfopsOr)
1698 	{  /*lint --e{715}*/
1699 	   SCIP_Bool violated;
1700 	   int i;
1701 	
1702 	   /* method is called only for integral solutions, because the enforcing priority is negative */
1703 	   for( i = 0; i < nconss; i++ )
1704 	   {
1705 	      SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
1706 	      if( violated )
1707 	      {
1708 	         *result = SCIP_INFEASIBLE;
1709 	         return SCIP_OKAY;
1710 	      }
1711 	   }
1712 	   *result = SCIP_FEASIBLE;
1713 	
1714 	   return SCIP_OKAY;
1715 	}
1716 	
1717 	
1718 	/** feasibility check method of constraint handler for integral solutions */
1719 	static
1720 	SCIP_DECL_CONSCHECK(consCheckOr)
1721 	{  /*lint --e{715}*/
1722 	   int i;
1723 	
1724 	   *result = SCIP_FEASIBLE;
1725 	
1726 	   /* method is called only for integral solutions, because the enforcing priority is negative */
1727 	   for( i = 0; i < nconss && (*result == SCIP_FEASIBLE || completely); i++ )
1728 	   {
1729 	      SCIP_Bool violated = FALSE;
1730 	
1731 	      SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
1732 	
1733 	      if( violated )
1734 	         *result = SCIP_INFEASIBLE;
1735 	   }
1736 	
1737 	   return SCIP_OKAY;
1738 	}
1739 	
1740 	
1741 	/** domain propagation method of constraint handler */
1742 	static
1743 	SCIP_DECL_CONSPROP(consPropOr)
1744 	{  /*lint --e{715}*/
1745 	   SCIP_CONSHDLRDATA* conshdlrdata;
1746 	   SCIP_Bool cutoff;
1747 	   int nfixedvars;
1748 	   int c;
1749 	
1750 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1751 	   assert(conshdlrdata != NULL);
1752 	
1753 	   cutoff = FALSE;
1754 	   nfixedvars = 0;
1755 	
1756 	   /* propagate all useful constraints */
1757 	   for( c = 0; c < nusefulconss && !cutoff; ++c )
1758 	   {
1759 	      SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata->eventhdlr, &cutoff, &nfixedvars) );
1760 	   }
1761 	
1762 	   /* return the correct result */
1763 	   if( cutoff )
1764 	      *result = SCIP_CUTOFF;
1765 	   else if( nfixedvars > 0 )
1766 	      *result = SCIP_REDUCEDDOM;
1767 	   else
1768 	      *result = SCIP_DIDNOTFIND;
1769 	
1770 	   return SCIP_OKAY;
1771 	}
1772 	
1773 	
1774 	/** presolving method of constraint handler */
1775 	static
1776 	SCIP_DECL_CONSPRESOL(consPresolOr)
1777 	{  /*lint --e{715}*/
1778 	   SCIP_CONSHDLRDATA* conshdlrdata;
1779 	   SCIP_CONS* cons;
1780 	   SCIP_CONSDATA* consdata;
1781 	   SCIP_Bool cutoff;
1782 	   SCIP_Bool redundant;
1783 	   SCIP_Bool aggregated;
1784 	   int oldnfixedvars;
1785 	   int oldnaggrvars;
1786 	   int oldnupgdconss;
1787 	   int c;
1788 	
1789 	   assert(result != NULL);
1790 	
1791 	   *result = SCIP_DIDNOTFIND;
1792 	   oldnfixedvars = *nfixedvars;
1793 	   oldnaggrvars = *naggrvars;
1794 	   oldnupgdconss = *nupgdconss;
1795 	
1796 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
1797 	   assert(conshdlrdata != NULL);
1798 	
1799 	   /* process constraints */
1800 	   cutoff = FALSE;
1801 	   for( c = 0; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
1802 	   {
1803 	      cons = conss[c];
1804 	      assert(cons != NULL);
1805 	      consdata = SCIPconsGetData(cons);
1806 	      assert(consdata != NULL);
1807 	
1808 	      /* force presolving the constraint in the initial round */
1809 	      if( nrounds == 0 )
1810 	         consdata->propagated = FALSE;
1811 	
1812 	      /* propagate constraint */
1813 	      SCIP_CALL( propagateCons(scip, cons, conshdlrdata->eventhdlr, &cutoff, nfixedvars) );
1814 	
1815 	      /* remove all variables that are fixed to one */
1816 	      SCIP_CALL( applyFixings(scip, cons, conshdlrdata->eventhdlr) );
1817 	
1818 	      /* transform or constraints into and constraints on the negated variables in order to improve
1819 	       * the pairwise constraint presolving possibilities
1820 	       */
1821 	      SCIP_CALL( upgradeCons(scip, cons, nupgdconss) );
1822 	
1823 	      if( !cutoff && !SCIPconsIsDeleted(cons) && !SCIPconsIsModifiable(cons) )
1824 	      {
1825 	         assert(consdata->nvars >= 1); /* otherwise, propagateCons() has deleted the constraint */
1826 	
1827 	         /* if only one variable is left, the resultant has to be equal to this single variable */
1828 	         if( consdata->nvars == 1 )
1829 	         {
1830 	            SCIPdebugMsg(scip, "or constraint <%s> has only one variable not fixed to 0.0\n", SCIPconsGetName(cons));
1831 	
1832 	            assert(consdata->vars != NULL);
1833 	            assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(consdata->vars[0]), 0.0));
1834 	            assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(consdata->vars[0]), 1.0));
1835 	
1836 	            /* aggregate variables: resultant - operand == 0 */
1837 	            SCIP_CALL( SCIPaggregateVars(scip, consdata->resvar, consdata->vars[0], 1.0, -1.0, 0.0,
1838 	                  &cutoff, &redundant, &aggregated) );
1839 	            assert(redundant || SCIPdoNotAggr(scip));
1840 	
1841 	            if( aggregated )
1842 	            {
1843 	               assert(redundant);
1844 	               (*naggrvars)++;
1845 	            }
1846 	
1847 	            if( redundant )
1848 	            {
1849 	               /* delete constraint */
1850 	               SCIP_CALL( SCIPdelCons(scip, cons) );
1851 	               (*ndelconss)++;
1852 	            }
1853 	         }
1854 	         else if( !consdata->impladded )
1855 	         {
1856 	            int i;
1857 	
1858 	            /* add implications: resultant == 0 -> all operands == 0 */
1859 	            for( i = 0; i < consdata->nvars && !cutoff; ++i )
1860 	            {
1861 	               int nimplbdchgs;
1862 	
1863 	               SCIP_CALL( SCIPaddVarImplication(scip, consdata->resvar, FALSE, consdata->vars[i],
1864 	                     SCIP_BOUNDTYPE_UPPER, 0.0, &cutoff, &nimplbdchgs) );
1865 	               *nchgbds += nimplbdchgs;
1866 	            }
1867 	            consdata->impladded = TRUE;
1868 	         }
1869 	
1870 	         /* if in r = x or y, the resultant is fixed to one, add implication x = 0 -> y = 1 */
1871 	         if( !cutoff && SCIPconsIsActive(cons) && consdata->nvars == 2 && !consdata->opimpladded
1872 	            && SCIPvarGetLbGlobal(consdata->resvar) > 0.5 )
1873 	         {
1874 	            int nimplbdchgs;
1875 	
1876 	            SCIP_CALL( SCIPaddVarImplication(scip, consdata->vars[0], FALSE, consdata->vars[1],
1877 	                  SCIP_BOUNDTYPE_LOWER, 1.0, &cutoff, &nimplbdchgs) );
1878 	            (*nchgbds) += nimplbdchgs;
1879 	            consdata->opimpladded = TRUE;
1880 	         }
1881 	      }
1882 	   }
1883 	
1884 	   /* return the correct result code */
1885 	   if( cutoff )
1886 	      *result = SCIP_CUTOFF;
1887 	   else if( *nfixedvars > oldnfixedvars || *naggrvars > oldnaggrvars || *nupgdconss > oldnupgdconss )
1888 	      *result = SCIP_SUCCESS;
1889 	
1890 	   return SCIP_OKAY;
1891 	}
1892 	
1893 	
1894 	/** propagation conflict resolving method of constraint handler */
1895 	static
1896 	SCIP_DECL_CONSRESPROP(consRespropOr)
1897 	{  /*lint --e{715}*/
1898 	   SCIP_CALL( resolvePropagation(scip, cons, infervar, (PROPRULE)inferinfo, bdchgidx, result) );
1899 	
1900 	   return SCIP_OKAY;
1901 	}
1902 	
1903 	
1904 	/** variable rounding lock method of constraint handler */
1905 	static
1906 	SCIP_DECL_CONSLOCK(consLockOr)
1907 	{  /*lint --e{715}*/
1908 	   SCIP_CONSDATA* consdata;
1909 	   int i;
1910 	
1911 	   assert(locktype == SCIP_LOCKTYPE_MODEL);
1912 	
1913 	   consdata = SCIPconsGetData(cons);
1914 	   assert(consdata != NULL);
1915 	
1916 	   /* lock resultant variable */
1917 	   SCIP_CALL( SCIPaddVarLocksType(scip, consdata->resvar, locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
1918 	
1919 	   /* lock all operand variables */
1920 	   for( i = 0; i < consdata->nvars; ++i )
1921 	   {
1922 	      SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
1923 	   }
1924 	
1925 	   return SCIP_OKAY;
1926 	}
1927 	
1928 	
1929 	/** constraint display method of constraint handler */
1930 	static
1931 	SCIP_DECL_CONSPRINT(consPrintOr)
1932 	{  /*lint --e{715}*/
1933 	   assert( scip != NULL );
1934 	   assert( conshdlr != NULL );
1935 	   assert( cons != NULL );
1936 	
1937 	   SCIP_CALL( consdataPrint(scip, SCIPconsGetData(cons), file) );
1938 	
1939 	   return SCIP_OKAY;
1940 	}
1941 	
1942 	/** constraint copying method of constraint handler */
1943 	static
1944 	SCIP_DECL_CONSCOPY(consCopyOr)
1945 	{  /*lint --e{715}*/
1946 	   SCIP_VAR** sourcevars;
1947 	   SCIP_VAR** vars;
1948 	   SCIP_VAR* sourceresvar;
1949 	   SCIP_VAR* resvar;
1950 	   int nvars;
1951 	   int v;
1952 	
1953 	   assert(valid != NULL);
1954 	   (*valid) = TRUE;
1955 	   resvar = NULL;
1956 	
1957 	   /* get variables that need to be copied */
1958 	   sourceresvar = SCIPgetResultantOr(sourcescip, sourcecons);
1959 	   sourcevars = SCIPgetVarsOr(sourcescip, sourcecons);
1960 	   nvars = SCIPgetNVarsOr(sourcescip, sourcecons);
1961 	
1962 	   if( nvars == -1 )
1963 	      return SCIP_INVALIDCALL;
1964 	
1965 	   /* allocate buffer array */
1966 	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1967 	
1968 	   /* map operand variables to active variables of the target SCIP */
1969 	   for( v = 0; v < nvars && *valid; ++v )
1970 	   {
1971 	      SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
1972 	      assert(!(*valid) || vars[v] != NULL);
1973 	   }
1974 	
1975 	   /* map resultant to active variable of the target SCIP  */
1976 	   if( *valid )
1977 	   {
1978 	      SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceresvar, &resvar, varmap, consmap, global, valid) );
1979 	      assert(!(*valid) || resvar != NULL);
1980 	
1981 	      if( *valid )
1982 	      {
1983 	         assert(resvar != NULL);
1984 	         SCIP_CALL( SCIPcreateConsOr(scip, cons, SCIPconsGetName(sourcecons), resvar, nvars, vars,
1985 	               initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1986 	      }
1987 	   }
1988 	
1989 	   /* free buffer array */
1990 	   SCIPfreeBufferArray(scip, &vars);
1991 	
1992 	   return SCIP_OKAY;
1993 	}
1994 	
1995 	/** constraint parsing method of constraint handler */
1996 	static
1997 	SCIP_DECL_CONSPARSE(consParseOr)
1998 	{  /*lint --e{715}*/
1999 	   SCIP_VAR** vars;
2000 	   SCIP_VAR* resvar;
2001 	   char* strcopy;
2002 	   char* token;
2003 	   char* saveptr;
2004 	   char* endptr;
2005 	   int requiredsize;
2006 	   int varssize;
2007 	   int nvars;
2008 	
2009 	   SCIPdebugMsg(scip, "parse <%s> as or constraint\n", str);
2010 	
2011 	   *success = FALSE;
2012 	
2013 	   /* copy string for truncating it */
2014 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &strcopy, str, (int)(strlen(str)+1)));
2015 	
2016 	   /* cutoff "or" form the constraint string */
2017 	   token = SCIPstrtok(strcopy, "=", &saveptr );
2018 	
2019 	   /* parse variable name */
2020 	   SCIP_CALL( SCIPparseVarName(scip, token, &resvar, &endptr) );
2021 	
2022 	   if( resvar == NULL )
2023 	   {
2024 	      SCIPerrorMessage("resultant variable does not exist\n");
2025 	   }
2026 	   else
2027 	   {
2028 	      /* cutoff "or" form the constraint string */
2029 	      (void) SCIPstrtok(NULL, "(", &saveptr );
2030 	
2031 	      /* cutoff ")" form the constraint string */
2032 	      token = SCIPstrtok(NULL, ")", &saveptr );
2033 	
2034 	      varssize = 100;
2035 	      nvars = 0;
2036 	
2037 	      /* allocate buffer array for variables */
2038 	      SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
2039 	
2040 	      /* parse string */
2041 	      SCIP_CALL( SCIPparseVarsList(scip, token, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
2042 	
2043 	      if( *success )
2044 	      {
2045 	         /* check if the size of the variable array was great enough */
2046 	         if( varssize < requiredsize )
2047 	         {
2048 	            /* reallocate memory */
2049 	            varssize = requiredsize;
2050 	            SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
2051 	
2052 	            /* parse string again with the correct size of the variable array */
2053 	            SCIP_CALL( SCIPparseVarsList(scip, token, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
2054 	         }
2055 	
2056 	         assert(*success);
2057 	         assert(varssize >= requiredsize);
2058 	
2059 	         /* create and constraint */
2060 	         SCIP_CALL( SCIPcreateConsOr(scip, cons, name, resvar, nvars, vars,
2061 	               initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
2062 	      }
2063 	
2064 	      /* free variable buffer */
2065 	      SCIPfreeBufferArray(scip, &vars);
2066 	   }
2067 	
2068 	   /* free string buffer */
2069 	   SCIPfreeBufferArray(scip, &strcopy);
2070 	
2071 	   return SCIP_OKAY;
2072 	}
2073 	
2074 	/** constraint method of constraint handler which returns the variables (if possible) */
2075 	static
2076 	SCIP_DECL_CONSGETVARS(consGetVarsOr)
2077 	{  /*lint --e{715}*/
2078 	   SCIP_CONSDATA* consdata;
2079 	
2080 	   consdata = SCIPconsGetData(cons);
2081 	   assert(consdata != NULL);
2082 	
2083 	   if( varssize < consdata->nvars + 1 )
2084 	      (*success) = FALSE;
2085 	   else
2086 	   {
2087 	      BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
2088 	      vars[consdata->nvars] = consdata->resvar;
2089 	      (*success) = TRUE;
2090 	   }
2091 	
2092 	   return SCIP_OKAY;
2093 	}
2094 	
2095 	/** constraint method of constraint handler which returns the number of variable (if possible) */
2096 	static
2097 	SCIP_DECL_CONSGETNVARS(consGetNVarsOr)
2098 	{  /*lint --e{715}*/
2099 	   SCIP_CONSDATA* consdata;
2100 	
2101 	   assert(cons != NULL);
2102 	
2103 	   consdata = SCIPconsGetData(cons);
2104 	   assert(consdata != NULL);
2105 	
2106 	   (*nvars) = consdata->nvars + 1;
2107 	   (*success) = TRUE;
2108 	
2109 	   return SCIP_OKAY;
2110 	}
2111 	
2112 	/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
2113 	static
2114 	SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphOr)
2115 	{  /*lint --e{715}*/
2116 	   SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
2117 	
2118 	   return SCIP_OKAY;
2119 	}
2120 	
2121 	/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
2122 	static
2123 	SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphOr)
2124 	{  /*lint --e{715}*/
2125 	   SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
2126 	
2127 	   return SCIP_OKAY;
2128 	}
2129 	
2130 	/*
2131 	 * Callback methods of event handler
2132 	 */
2133 	
2134 	static
2135 	SCIP_DECL_EVENTEXEC(eventExecOr)
2136 	{  /*lint --e{715}*/
2137 	   SCIP_CONSDATA* consdata;
2138 	
2139 	   assert(eventhdlr != NULL);
2140 	   assert(eventdata != NULL);
2141 	   assert(event != NULL);
2142 	
2143 	   consdata = (SCIP_CONSDATA*)eventdata;
2144 	   assert(consdata != NULL);
2145 	
2146 	   /* check, if the variable was fixed to one */
2147 	   if( SCIPeventGetType(event) == SCIP_EVENTTYPE_LBTIGHTENED )
2148 	      consdata->nofixedone = FALSE;
2149 	
2150 	   consdata->propagated = FALSE;
2151 	
2152 	   return SCIP_OKAY;
2153 	}
2154 	
2155 	
2156 	/*
2157 	 * constraint specific interface methods
2158 	 */
2159 	
2160 	/** creates the handler for or constraints and includes it in SCIP */
2161 	SCIP_RETCODE SCIPincludeConshdlrOr(
2162 	   SCIP*                 scip                /**< SCIP data structure */
2163 	   )
2164 	{
2165 	   SCIP_CONSHDLRDATA* conshdlrdata;
2166 	   SCIP_CONSHDLR* conshdlr;
2167 	   SCIP_EVENTHDLR* eventhdlr;
2168 	
2169 	   /* create event handler for events on variables */
2170 	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
2171 	         eventExecOr, NULL) );
2172 	
2173 	   /* create constraint handler data */
2174 	   SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
2175 	
2176 	   /* include constraint handler */
2177 	   SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
2178 	         CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
2179 	         consEnfolpOr, consEnfopsOr, consCheckOr, consLockOr,
2180 	         conshdlrdata) );
2181 	   assert(conshdlr != NULL);
2182 	
2183 	   /* set non-fundamental callbacks via specific setter functions */
2184 	   SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyOr, consCopyOr) );
2185 	   SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteOr) );
2186 	   SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolOr) );
2187 	   SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeOr) );
2188 	   SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsOr) );
2189 	   SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsOr) );
2190 	   SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpOr) );
2191 	   SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseOr) );
2192 	   SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolOr, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
2193 	   SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintOr) );
2194 	   SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropOr, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
2195 	         CONSHDLR_PROP_TIMING) );
2196 	   SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropOr) );
2197 	   SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpOr, consSepasolOr, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY,
2198 	         CONSHDLR_DELAYSEPA) );
2199 	   SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransOr) );
2200 	   SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxOr) );
2201 	   SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphOr) );
2202 	   SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphOr) );
2203 	
2204 	   return SCIP_OKAY;
2205 	}
2206 	
2207 	/** creates and captures an or constraint
2208 	 *
2209 	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
2210 	 */
2211 	SCIP_RETCODE SCIPcreateConsOr(
2212 	   SCIP*                 scip,               /**< SCIP data structure */
2213 	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
2214 	   const char*           name,               /**< name of constraint */
2215 	   SCIP_VAR*             resvar,             /**< resultant variable of the operation */
2216 	   int                   nvars,              /**< number of operator variables in the constraint */
2217 	   SCIP_VAR**            vars,               /**< array with operator variables of constraint */
2218 	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
2219 	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
2220 	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
2221 	                                              *   Usually set to TRUE. */
2222 	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
2223 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
2224 	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
2225 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
2226 	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
2227 	                                              *   Usually set to TRUE. */
2228 	   SCIP_Bool             local,              /**< is constraint only valid locally?
2229 	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
2230 	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
2231 	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
2232 	                                              *   adds coefficients to this constraint. */
2233 	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
2234 	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
2235 	                                              *   are separated as constraints. */
2236 	   SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
2237 	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
2238 	   SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
2239 	                                              *   if it may be moved to a more global node?
2240 	                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
2241 	   )
2242 	{
2243 	   SCIP_CONSHDLR* conshdlr;
2244 	   SCIP_CONSHDLRDATA* conshdlrdata;
2245 	   SCIP_CONSDATA* consdata;
2246 	
2247 	   /* find the or constraint handler */
2248 	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
2249 	   if( conshdlr == NULL )
2250 	   {
2251 	      SCIPerrorMessage("or constraint handler not found\n");
2252 	      return SCIP_PLUGINNOTFOUND;
2253 	   }
2254 	
2255 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2256 	   assert(conshdlrdata != NULL);
2257 	
2258 	   /* create constraint data */
2259 	   SCIP_CALL( consdataCreate(scip, &consdata, conshdlrdata->eventhdlr, nvars, vars, resvar) );
2260 	
2261 	   /* create constraint */
2262 	   SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
2263 	         local, modifiable, dynamic, removable, stickingatnode) );
2264 	
2265 	   return SCIP_OKAY;
2266 	}
2267 	
2268 	/** creates and captures an or constraint
2269 	 *  in its most basic variant, i. e., with all constraint flags set to their default values
2270 	 *
2271 	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
2272 	 */
2273 	SCIP_RETCODE SCIPcreateConsBasicOr(
2274 	   SCIP*                 scip,               /**< SCIP data structure */
2275 	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
2276 	   const char*           name,               /**< name of constraint */
2277 	   SCIP_VAR*             resvar,             /**< resultant variable of the operation */
2278 	   int                   nvars,              /**< number of operator variables in the constraint */
2279 	   SCIP_VAR**            vars                /**< array with operator variables of constraint */
2280 	   )
2281 	{
2282 	   SCIP_CALL( SCIPcreateConsOr(scip, cons, name, resvar, nvars, vars, TRUE, TRUE, TRUE, TRUE, TRUE,
2283 	         FALSE, FALSE, FALSE, FALSE, FALSE) );
2284 	
2285 	   return SCIP_OKAY;
2286 	}
2287 	
2288 	/** gets number of variables in or constraint */
2289 	int SCIPgetNVarsOr(
2290 	   SCIP*                 scip,               /**< SCIP data structure */
2291 	   SCIP_CONS*            cons                /**< constraint data */
2292 	   )
2293 	{
2294 	   SCIP_CONSDATA* consdata;
2295 	
2296 	   assert(scip != NULL);
2297 	
2298 	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
2299 	   {
2300 	      SCIPerrorMessage("constraint is not an or constraint\n");
2301 	      SCIPABORT();
2302 	      return -1;  /*lint !e527*/
2303 	   }
2304 	
2305 	   consdata = SCIPconsGetData(cons);
2306 	   assert(consdata != NULL);
2307 	
2308 	   return consdata->nvars;
2309 	}
2310 	
2311 	/** gets array of variables in or constraint */
2312 	SCIP_VAR** SCIPgetVarsOr(
2313 	   SCIP*                 scip,               /**< SCIP data structure */
2314 	   SCIP_CONS*            cons                /**< constraint data */
2315 	   )
2316 	{
2317 	   SCIP_CONSDATA* consdata;
2318 	
2319 	   assert(scip != NULL);
2320 	
2321 	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
2322 	   {
2323 	      SCIPerrorMessage("constraint is not an or constraint\n");
2324 	      SCIPABORT();
2325 	      return NULL;  /*lint !e527*/
2326 	   }
2327 	
2328 	   consdata = SCIPconsGetData(cons);
2329 	   assert(consdata != NULL);
2330 	
2331 	   return consdata->vars;
2332 	}
2333 	
2334 	/** gets the resultant variable in or constraint */
2335 	SCIP_VAR* SCIPgetResultantOr(
2336 	   SCIP*                 scip,               /**< SCIP data structure */
2337 	   SCIP_CONS*            cons                /**< constraint data */
2338 	   )
2339 	{
2340 	   SCIP_CONSDATA* consdata;
2341 	
2342 	   assert(scip != NULL);
2343 	
2344 	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
2345 	   {
2346 	      SCIPerrorMessage("constraint is not a or constraint\n");
2347 	      SCIPABORT();
2348 	      return NULL;  /*lint !e527*/
2349 	   }
2350 	
2351 	   consdata = SCIPconsGetData(cons);
2352 	   assert(consdata != NULL);
2353 	
2354 	   return consdata->resvar;
2355 	}
2356