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_cumulative.c
26   	 * @ingroup DEFPLUGINS_CONS
27   	 * @brief  constraint handler for cumulative constraints
28   	 * @author Timo Berthold
29   	 * @author Stefan Heinz
30   	 * @author Jens Schulz
31   	 *
32   	 * Given:
33   	 * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
34   	 *   their demands \f$d_j\f$.
35   	 * - an integer resource capacity \f$C\f$
36   	 *
37   	 * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
38   	 *
39   	 * Separation:
40   	 * - can be done using binary start time model, see Pritskers, Watters and Wolfe
41   	 * - or by just separating relatively weak cuts on the integer start time variables
42   	 *
43   	 * Propagation:
44   	 * - time tabling, Klein & Scholl (1999)
45   	 * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
46   	 *   (2009)
47   	 * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
48   	 *
49   	 */
50   	
51   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
52   	
53   	#include <assert.h>
54   	#include <string.h>
55   	
56   	#include "tclique/tclique.h"
57   	#include "scip/cons_cumulative.h"
58   	#include "scip/cons_linking.h"
59   	#include "scip/cons_knapsack.h"
60   	#include "scip/scipdefplugins.h"
61   	
62   	/**@name Constraint handler properties
63   	 *
64   	 * @{
65   	 */
66   	
67   	/* constraint handler properties */
68   	#define CONSHDLR_NAME          "cumulative"
69   	#define CONSHDLR_DESC          "cumulative constraint handler"
70   	#define CONSHDLR_SEPAPRIORITY   2100000 /**< priority of the constraint handler for separation */
71   	#define CONSHDLR_ENFOPRIORITY  -2040000 /**< priority of the constraint handler for constraint enforcing */
72   	#define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
73   	#define CONSHDLR_SEPAFREQ             1 /**< frequency for separating cuts; zero means to separate only in the root node */
74   	#define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
75   	#define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
76   	                                         *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
77   	#define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
78   	#define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
79   	#define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
80   	#define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
81   	
82   	#define CONSHDLR_PRESOLTIMING            SCIP_PRESOLTIMING_ALWAYS
83   	#define CONSHDLR_PROP_TIMING             SCIP_PROPTIMING_BEFORELP
84   	
85   	/**@} */
86   	
87   	/**@name Default parameter values
88   	 *
89   	 * @{
90   	 */
91   	
92   	/* default parameter values */
93   	
94   	/* separation */
95   	#define DEFAULT_USEBINVARS             FALSE /**< should the binary representation be used? */
96   	#define DEFAULT_LOCALCUTS              FALSE /**< should cuts be added only locally? */
97   	#define DEFAULT_USECOVERCUTS            TRUE /**< should covering cuts be added? */
98   	#define DEFAULT_CUTSASCONSS             TRUE /**< should the cuts be created as knapsack constraints? */
99   	#define DEFAULT_SEPAOLD                 TRUE /**< shall old sepa algo be applied? */
100  	
101  	/* propagation */
102  	#define DEFAULT_TTINFER                 TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
103  	#define DEFAULT_EFCHECK                FALSE /**< should edge-finding be used to detect an overload? */
104  	#define DEFAULT_EFINFER                FALSE /**< should edge-finding be used to infer bounds? */
105  	#define DEFAULT_USEADJUSTEDJOBS        FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
106  	#define DEFAULT_TTEFCHECK               TRUE /**< should time-table edge-finding be used to detect an overload? */
107  	#define DEFAULT_TTEFINFER               TRUE /**< should time-table edge-finding be used to infer bounds? */
108  	
109  	/* presolving */
110  	#define DEFAULT_DUALPRESOLVE            TRUE /**< should dual presolving be applied? */
111  	#define DEFAULT_COEFTIGHTENING         FALSE /**< should coeffisient tightening be applied? */
112  	#define DEFAULT_NORMALIZE               TRUE /**< should demands and capacity be normalized? */
113  	#define DEFAULT_PRESOLPAIRWISE          TRUE /**< should pairwise constraint comparison be performed in presolving? */
114  	#define DEFAULT_DISJUNCTIVE             TRUE /**< extract disjunctive constraints? */
115  	#define DEFAULT_DETECTDISJUNCTIVE       TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
116  	#define DEFAULT_DETECTVARBOUNDS         TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
117  	#define DEFAULT_MAXNODES             10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint  (-1: no limit) */
118  	
119  	/* enforcement */
120  	#define DEFAULT_FILLBRANCHCANDS        FALSE /**< should branching candidates be added to storage? */
121  	
122  	/* conflict analysis */
123  	#define DEFAULT_USEBDWIDENING           TRUE /**< should bound widening be used during conflict analysis? */
124  	
125  	/**@} */
126  	
127  	/**@name Event handler properties
128  	 *
129  	 * @{
130  	 */
131  	
132  	#define EVENTHDLR_NAME         "cumulative"
133  	#define EVENTHDLR_DESC         "bound change event handler for cumulative constraints"
134  	
135  	/**@} */
136  	
137  	/*
138  	 * Data structures
139  	 */
140  	
141  	/** constraint data for cumulative constraints */
142  	struct SCIP_ConsData
143  	{
144  	   SCIP_VAR**            vars;               /**< array of variable representing the start time of each job */
145  	   SCIP_Bool*            downlocks;          /**< array to store if the variable has a down lock */
146  	   SCIP_Bool*            uplocks;            /**< array to store if the variable has an uplock */
147  	   SCIP_CONS**           linkingconss;       /**< array of linking constraints for the integer variables */
148  	   SCIP_ROW**            demandrows;         /**< array of rows of linear relaxation of this problem */
149  	   SCIP_ROW**            scoverrows;         /**< array of rows of small cover cuts of this problem */
150  	   SCIP_ROW**            bcoverrows;         /**< array of rows of big cover cuts of this problem */
151  	   int*                  demands;            /**< array containing corresponding demands */
152  	   int*                  durations;          /**< array containing corresponding durations */
153  	   SCIP_Real             resstrength1;       /**< stores the resource strength 1*/
154  	   SCIP_Real             resstrength2;       /**< stores the resource strength 2 */
155  	   SCIP_Real             cumfactor1;         /**< stroes the cumulativeness of the constraint */
156  	   SCIP_Real             disjfactor1;        /**< stores the disjunctiveness of the constraint */
157  	   SCIP_Real             disjfactor2;        /**< stores the disjunctiveness of the constraint */
158  	   SCIP_Real             estimatedstrength;
159  	   int                   nvars;              /**< number of variables */
160  	   int                   varssize;           /**< size of the arrays */
161  	   int                   ndemandrows;        /**< number of rows of cumulative constrint for linear relaxation */
162  	   int                   demandrowssize;     /**< size of array rows of demand rows */
163  	   int                   nscoverrows;        /**< number of rows of small cover cuts */
164  	   int                   scoverrowssize;     /**< size of array of small cover cuts */
165  	   int                   nbcoverrows;        /**< number of rows of big cover cuts */
166  	   int                   bcoverrowssize;     /**< size of array of big cover cuts */
167  	   int                   capacity;           /**< available cumulative capacity */
168  	
169  	   int                   hmin;               /**< left bound of time axis to be considered (including hmin) */
170  	   int                   hmax;               /**< right bound of time axis to be considered  (not including hmax) */
171  	
172  	   unsigned int          signature;          /**< constraint signature which is need for pairwise comparison */
173  	
174  	   unsigned int          validsignature:1;   /**< is the signature valid */
175  	   unsigned int          normalized:1;       /**< is the constraint normalized */
176  	   unsigned int          covercuts:1;        /**< cover cuts are created? */
177  	   unsigned int          propagated:1;       /**< is constraint propagted */
178  	   unsigned int          varbounds:1;        /**< bool to store if variable bound strengthening was already preformed */
179  	   unsigned int          triedsolving:1;     /**< bool to store if we tried already to solve that constraint as independent subproblem */
180  	
181  	#ifdef SCIP_STATISTIC
182  	   int                   maxpeak;
183  	#endif
184  	};
185  	
186  	/** constraint handler data */
187  	struct SCIP_ConshdlrData
188  	{
189  	   SCIP_EVENTHDLR*       eventhdlr;          /**< event handler for bound change events */
190  	
191  	   SCIP_Bool             usebinvars;         /**< should the binary variables be used? */
192  	   SCIP_Bool             cutsasconss;        /**< should the cumulative constraint create cuts as knapsack constraints? */
193  	   SCIP_Bool             ttinfer;            /**< should time-table (core-times) propagator be used to infer bounds? */
194  	   SCIP_Bool             efcheck;            /**< should edge-finding be used to detect an overload? */
195  	   SCIP_Bool             efinfer;            /**< should edge-finding be used to infer bounds? */
196  	   SCIP_Bool             useadjustedjobs;    /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
197  	   SCIP_Bool             ttefcheck;          /**< should time-table edge-finding be used to detect an overload? */
198  	   SCIP_Bool             ttefinfer;          /**< should time-table edge-finding be used to infer bounds? */
199  	   SCIP_Bool             localcuts;          /**< should cuts be added only locally? */
200  	   SCIP_Bool             usecovercuts;       /**< should covering cuts be added? */
201  	   SCIP_Bool             sepaold;            /**< shall old sepa algo be applied? */
202  	
203  	   SCIP_Bool             fillbranchcands;    /**< should branching candidates be added to storage? */
204  	
205  	   SCIP_Bool             dualpresolve;       /**< should dual presolving be applied? */
206  	   SCIP_Bool             coeftightening;     /**< should coeffisient tightening be applied? */
207  	   SCIP_Bool             normalize;          /**< should demands and capacity be normalized? */
208  	   SCIP_Bool             disjunctive;        /**< extract disjunctive constraints? */
209  	   SCIP_Bool             detectdisjunctive;  /**< search for conflict set via maximal cliques to detect disjunctive constraints */
210  	   SCIP_Bool             detectvarbounds;    /**< search for conflict set via maximal cliques to detect variable bound constraints */
211  	   SCIP_Bool             usebdwidening;      /**< should bound widening be used during conflict analysis? */
212  	   SCIP_Bool             presolpairwise;     /**< should pairwise constraint comparison be performed in presolving? */
213  	   SCIP_Bool             detectedredundant;  /**< was detection of redundant constraints already performed? */
214  	
215  	   SCIP_Longint          maxnodes;           /**< number of branch-and-bound nodes to solve an independent cumulative constraint  (-1: no limit) */
216  	
217  	   SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
218  	
219  	   /* statistic values which are collected if SCIP_STATISTIC is defined */
220  	#ifdef SCIP_STATISTIC
221  	   SCIP_Longint          nlbtimetable;       /**< number of times the lower bound was tightened by the time-table propagator */
222  	   SCIP_Longint          nubtimetable;       /**< number of times the upper bound was tightened by the time-table propagator */
223  	   SCIP_Longint          ncutofftimetable;   /**< number of times the a cutoff was detected due to time-table propagator */
224  	   SCIP_Longint          nlbedgefinder;      /**< number of times the lower bound was tightened by the edge-finder propagator */
225  	   SCIP_Longint          nubedgefinder;      /**< number of times the upper bound was tightened by the edge-finder propagator */
226  	   SCIP_Longint          ncutoffedgefinder;  /**< number of times the a cutoff was detected due to edge-finder propagator */
227  	   SCIP_Longint          ncutoffoverload;    /**< number of times the a cutoff was detected due to overload checking via edge-finding */
228  	   SCIP_Longint          nlbTTEF;            /**< number of times the lower bound was tightened by time-table edge-finding */
229  	   SCIP_Longint          nubTTEF;            /**< number of times the upper bound was tightened by time-table edge-finding */
230  	   SCIP_Longint          ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
231  	
232  	   int                   nirrelevantjobs;    /**< number of time a irrelevant/redundant jobs was removed form a constraint */
233  	   int                   nalwaysruns;        /**< number of time a job removed form a constraint which run completely during the effective horizon */
234  	   int                   nremovedlocks;      /**< number of times a up or down lock was removed */
235  	   int                   ndualfixs;          /**< number of times a dual fix was performed by a single constraint */
236  	   int                   ndecomps;           /**< number of times a constraint was decomposed */
237  	   int                   ndualbranchs;       /**< number of times a dual branch was discoverd and applicable via probing */
238  	   int                   nallconsdualfixs;   /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
239  	   int                   naddedvarbounds;    /**< number of added variable bounds constraints */
240  	   int                   naddeddisjunctives; /**< number of added disjunctive constraints */
241  	
242  	   SCIP_Bool             iscopy;             /**< Boolean to store if constraint handler is part of a copy */
243  	#endif
244  	};
245  	
246  	/**@name Inference Information Methods
247  	 *
248  	 *  An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
249  	 *  constraint handler if the corresponding bound change has to be explained. It can be used to store information which
250  	 *  help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
251  	 *
252  	 *  In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
253  	 *  change and the earliest start and latest completion time of all jobs in the conflict set.
254  	 *
255  	 * @{
256  	 */
257  	
258  	/** Propagation rules */
259  	enum Proprule
260  	{
261  	   PROPRULE_0_INVALID            = 0,        /**< invalid inference information */
262  	   PROPRULE_1_CORETIMES          = 1,        /**< core-time propagator */
263  	   PROPRULE_2_EDGEFINDING        = 2,        /**< edge-finder */
264  	   PROPRULE_3_TTEF               = 3         /**< time-table edeg-finding */
265  	};
266  	typedef enum Proprule PROPRULE;
267  	
268  	/** inference information */
269  	struct InferInfo
270  	{
271  	   union
272  	   {
273  	      /** struct to use the inference information */
274  	      struct
275  	      {
276  	         unsigned int    proprule:2;         /**< propagation rule that was applied */
277  	         unsigned int    data1:15;           /**< data field one */
278  	         unsigned int    data2:15;           /**< data field two */
279  	      } asbits;
280  	      int                asint;              /**< inference information as a single int value */
281  	   } val;
282  	};
283  	typedef struct InferInfo INFERINFO;
284  	
285  	/** converts an integer into an inference information */
286  	static
287  	INFERINFO intToInferInfo(
288  	   int                   i                   /**< integer to convert */
289  	   )
290  	{
291  	   INFERINFO inferinfo;
292  	
293  	   inferinfo.val.asint = i;
294  	
295  	   return inferinfo;
296  	}
297  	
298  	/** converts an inference information into an int */
299  	static
300  	int inferInfoToInt(
301  	   INFERINFO             inferinfo           /**< inference information to convert */
302  	   )
303  	{
304  	   return inferinfo.val.asint;
305  	}
306  	
307  	/** returns the propagation rule stored in the inference information */
308  	static
309  	PROPRULE inferInfoGetProprule(
310  	   INFERINFO             inferinfo           /**< inference information to convert */
311  	   )
312  	{
313  	   return (PROPRULE) inferinfo.val.asbits.proprule;
314  	}
315  	
316  	/** returns data field one of the inference information */
317  	static
318  	int inferInfoGetData1(
319  	   INFERINFO             inferinfo           /**< inference information to convert */
320  	   )
321  	{
322  	   return (int) inferinfo.val.asbits.data1;
323  	}
324  	
325  	/** returns data field two of the inference information */
326  	static
327  	int inferInfoGetData2(
328  	   INFERINFO             inferinfo           /**< inference information to convert */
329  	   )
330  	{
331  	   return (int) inferinfo.val.asbits.data2;
332  	}
333  	
334  	/** returns whether the inference information is valid */
335  	static
336  	SCIP_Bool inferInfoIsValid(
337  	   INFERINFO             inferinfo           /**< inference information to convert */
338  	   )
339  	{
340  	   return (inferinfo.val.asint != 0);
341  	}
342  	
343  	
344  	/** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
345  	static
346  	INFERINFO getInferInfo(
347  	   PROPRULE              proprule,           /**< propagation rule that deduced the value */
348  	   int                   data1,              /**< data field one */
349  	   int                   data2               /**< data field two */
350  	   )
351  	{
352  	   INFERINFO inferinfo;
353  	
354  	   /* check that the data members are in the range of the available bits */
355  	   if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
356  	   {
357  	      inferinfo.val.asint = 0;
358  	      assert(inferInfoGetProprule(inferinfo) == PROPRULE_0_INVALID);
359  	      assert(inferInfoIsValid(inferinfo) == FALSE);
360  	   }
361  	   else
362  	   {
363  	      inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
364  	      inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
365  	      inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
366  	      assert(inferInfoIsValid(inferinfo) == TRUE);
367  	   }
368  	
369  	   return inferinfo;
370  	}
371  	
372  	/**@} */
373  	
374  	/*
375  	 * Local methods
376  	 */
377  	
378  	/**@name Miscellaneous Methods
379  	 *
380  	 * @{
381  	 */
382  	
383  	#ifndef NDEBUG
384  	
385  	/** compute the core of a job which lies in certain interval [begin, end) */
386  	static
387  	SCIP_Longint computeCoreWithInterval(
388  	   int                   begin,              /**< begin of the interval */
389  	   int                   end,                /**< end of the interval */
390  	   int                   ect,                /**< earliest completion time */
391  	   int                   lst                 /**< latest start time */
392  	   )
393  	{
394  	   int core;
395  	
396  	   core = MAX(0, MIN(end, ect) - MAX(lst, begin));
397  	
398  	   return core;
399  	}
400  	#else
401  	#define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
402  	#endif
403  	
404  	/** returns the implied earliest start time */   /*lint -e{715}*/
405  	static
406  	SCIP_RETCODE computeImpliedEst(
407  	   SCIP*                 scip,               /**< SCIP data structure */
408  	   SCIP_VAR*             var,                /**< variable for which the implied est should be returned */
409  	   SCIP_HASHMAP*         addedvars,          /**< hash map containig the variable which are already added */
410  	   int*                  est                 /**< pointer to store the implied earliest start time */
411  	   )
412  	{  /*lint --e{715}*/
413  	#if 0
414  	   SCIP_VAR** vbdvars;
415  	   SCIP_VAR* vbdvar;
416  	   SCIP_Real* vbdcoefs;
417  	   SCIP_Real* vbdconsts;
418  	   void* image;
419  	   int nvbdvars;
420  	   int v;
421  	#endif
422  	
423  	   (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
424  	
425  	#if 0
426  	   /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
427  	
428  	   nvbdvars = SCIPvarGetNVlbs(var);
429  	   vbdvars = SCIPvarGetVlbVars(var);
430  	   vbdcoefs = SCIPvarGetVlbCoefs(var);
431  	   vbdconsts = SCIPvarGetVlbConstants(var);
432  	
433  	   for( v = 0; v < nvbdvars; ++v )
434  	   {
435  	      vbdvar = vbdvars[v];
436  	      assert(vbdvar != NULL);
437  	
438  	      image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
439  	
440  	      if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
441  	      {
442  	         int duration;
443  	         int vbdconst;
444  	
445  	         duration = (int)(size_t)image;
446  	         vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
447  	
448  	         SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
449  	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
450  	            SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
451  	
452  	         if( duration >= vbdconst )
453  	         {
454  	            int impliedest;
455  	
456  	            impliedest =  SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
457  	
458  	            if( (*est) < impliedest )
459  	            {
460  	               (*est) = impliedest;
461  	
462  	               SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
463  	            }
464  	         }
465  	      }
466  	   }
467  	#endif
468  	
469  	   return SCIP_OKAY;
470  	}
471  	
472  	/** returns the implied latest completion time */    /*lint -e{715}*/
473  	static
474  	SCIP_RETCODE computeImpliedLct(
475  	   SCIP*                 scip,               /**< SCIP data structure */
476  	   SCIP_VAR*             var,                /**< variable for which the implied est should be returned */
477  	   int                   duration,           /**< duration of the given job */
478  	   SCIP_HASHMAP*         addedvars,          /**< hash map containig the variable which are already added */
479  	   int*                  lct                 /**< pointer to store the implied latest completion time */
480  	   )
481  	{  /*lint --e{715}*/
482  	#if 0
483  	   SCIP_VAR** vbdvars;
484  	   SCIP_VAR* vbdvar;
485  	   SCIP_Real* vbdcoefs;
486  	   SCIP_Real* vbdconsts;
487  	   int nvbdvars;
488  	   int v;
489  	#endif
490  	
491  	   (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
492  	
493  	#if 0
494  	   /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
495  	
496  	   nvbdvars = SCIPvarGetNVubs(var);
497  	   vbdvars = SCIPvarGetVubVars(var);
498  	   vbdcoefs = SCIPvarGetVubCoefs(var);
499  	   vbdconsts = SCIPvarGetVubConstants(var);
500  	
501  	   for( v = 0; v < nvbdvars; ++v )
502  	   {
503  	      vbdvar = vbdvars[v];
504  	      assert(vbdvar != NULL);
505  	
506  	      if( SCIPhashmapExists(addedvars, (void*)vbdvar) &&  SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
507  	      {
508  	         int vbdconst;
509  	
510  	         vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
511  	
512  	         SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
513  	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
514  	            SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
515  	
516  	         if( duration >= -vbdconst )
517  	         {
518  	            int impliedlct;
519  	
520  	            impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
521  	
522  	            if( (*lct) > impliedlct )
523  	            {
524  	               (*lct) = impliedlct;
525  	
526  	               SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
527  	            }
528  	         }
529  	      }
530  	   }
531  	#endif
532  	
533  	   return SCIP_OKAY;
534  	}
535  	
536  	/** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
537  	static
538  	SCIP_RETCODE collectBinaryVars(
539  	   SCIP*                 scip,               /**< SCIP data structure */
540  	   SCIP_CONSDATA*        consdata,           /**< constraint data */
541  	   SCIP_VAR***           vars,               /**< pointer to the array to store the binary variables */
542  	   int**                 coefs,              /**< pointer to store the coefficients */
543  	   int*                  nvars,              /**< number if collect binary variables */
544  	   int*                  startindices,       /**< permutation with rspect to the start times */
545  	   int                   curtime,            /**< current point in time */
546  	   int                   nstarted,           /**< number of jobs that start before the curtime or at curtime */
547  	   int                   nfinished           /**< number of jobs that finished before curtime or at curtime */
548  	   )
549  	{
550  	   int nrowvars;
551  	   int startindex;
552  	   int size;
553  	
554  	   size = 10;
555  	   nrowvars = 0;
556  	   startindex = nstarted - 1;
557  	
558  	   SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
559  	   SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
560  	
561  	   /* search for the (nstarted - nfinished) jobs which are active at curtime */
562  	   while( nstarted - nfinished > nrowvars )
563  	   {
564  	      SCIP_VAR* var;
565  	      int endtime;
566  	      int duration;
567  	      int demand;
568  	      int varidx;
569  	
570  	      /* collect job information */
571  	      varidx = startindices[startindex];
572  	      assert(varidx >= 0 && varidx < consdata->nvars);
573  	
574  	      var = consdata->vars[varidx];
575  	      duration = consdata->durations[varidx];
576  	      demand = consdata->demands[varidx];
577  	      assert(var != NULL);
578  	
579  	      endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
580  	
581  	      /* check the end time of this job is larger than the curtime; in this case the job is still running */
582  	      if( endtime > curtime )
583  	      {
584  	         SCIP_VAR** binvars;
585  	         SCIP_Real* vals;
586  	         int nbinvars;
587  	         int start;
588  	         int end;
589  	         int b;
590  	
591  	         /* check if the linking constraints exists */
592  	         assert(SCIPexistsConsLinking(scip, var));
593  	         assert(SCIPgetConsLinking(scip, var) != NULL);
594  	         assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
595  	
596  	         /* collect linking constraint information */
597  	         SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
598  	         vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
599  	
600  	         start = curtime - duration + 1;
601  	         end = MIN(curtime, endtime - duration);
602  	
603  	         for( b = 0; b < nbinvars; ++b )
604  	         {
605  	            if( vals[b] < start )
606  	               continue;
607  	
608  	            if( vals[b] > end )
609  	               break;
610  	
611  	            assert(binvars[b] != NULL);
612  	
613  	            /* ensure array proper array size */
614  	            if( size == *nvars )
615  	            {
616  	               size *= 2;
617  	               SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
618  	               SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
619  	            }
620  	
621  	            (*vars)[*nvars] = binvars[b];
622  	            (*coefs)[*nvars] = demand;
623  	            (*nvars)++;
624  	         }
625  	         nrowvars++;
626  	      }
627  	
628  	      startindex--;
629  	   }
630  	
631  	   return SCIP_OKAY;
632  	}
633  	
634  	/** collect all integer variable which belong to jobs which can run at the point of interest */
635  	static
636  	SCIP_RETCODE collectIntVars(
637  	   SCIP*                 scip,               /**< SCIP data structure */
638  	   SCIP_CONSDATA*        consdata,           /**< constraint data */
639  	   SCIP_VAR***           activevars,         /**< jobs that are currently running */
640  	   int*                  startindices,       /**< permutation with rspect to the start times */
641  	   int                   curtime,            /**< current point in time */
642  	   int                   nstarted,           /**< number of jobs that start before the curtime or at curtime */
643  	   int                   nfinished,          /**< number of jobs that finished before curtime or at curtime */
644  	   SCIP_Bool             lower,              /**< shall cuts be created due to lower or upper bounds? */
645  	   int*                  lhs                 /**< lhs for the new row sum of lbs + minoffset */
646  	   )
647  	{
648  	   SCIP_VAR* var;
649  	   int startindex;
650  	   int endtime;
651  	   int duration;
652  	   int starttime;
653  	
654  	   int varidx;
655  	   int sumofstarts;
656  	   int mindelta;
657  	   int counter;
658  	
659  	   assert(curtime >= consdata->hmin);
660  	   assert(curtime < consdata->hmax);
661  	
662  	   counter = 0;
663  	   sumofstarts = 0;
664  	
665  	   mindelta = INT_MAX;
666  	
667  	   startindex = nstarted - 1;
668  	
669  	   /* search for the (nstarted - nfinished) jobs which are active at curtime */
670  	   while( nstarted - nfinished > counter )
671  	   {
672  	      assert(startindex >= 0);
673  	
674  	      /* collect job information */
675  	      varidx = startindices[startindex];
676  	      assert(varidx >= 0 && varidx < consdata->nvars);
677  	
678  	      var = consdata->vars[varidx];
679  	      duration = consdata->durations[varidx];
680  	      assert(duration > 0);
681  	      assert(var != NULL);
682  	
683  	      if( lower )
684  	         starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
685  	      else
686  	         starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
687  	
688  	      endtime = MIN(starttime + duration, consdata->hmax);
689  	
690  	      /* check the end time of this job is larger than the curtime; in this case the job is still running */
691  	      if( endtime > curtime )
692  	      {
693  	         (*activevars)[counter] = var;
694  	         sumofstarts += starttime;
695  	         mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
696  	         counter++;
697  	      }
698  	
699  	      startindex--;
700  	   }
701  	
702  	   assert(mindelta > 0);
703  	   *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
704  	
705  	   return SCIP_OKAY;
706  	}
707  	
708  	/** initialize the sorted event point arrays */
709  	static
710  	void createSortedEventpoints(
711  	   SCIP*                 scip,               /**< SCIP data structure */
712  	   int                   nvars,              /**< number of start time variables (activities) */
713  	   SCIP_VAR**            vars,               /**< array of start time variables */
714  	   int*                  durations,          /**< array of durations per start time variable */
715  	   int*                  starttimes,         /**< array to store sorted start events */
716  	   int*                  endtimes,           /**< array to store sorted end events */
717  	   int*                  startindices,       /**< permutation with rspect to the start times */
718  	   int*                  endindices,         /**< permutation with rspect to the end times */
719  	   SCIP_Bool             local               /**< shall local bounds be used */
720  	   )
721  	{
722  	   SCIP_VAR* var;
723  	   int j;
724  	
725  	   assert(vars != NULL || nvars == 0);
726  	
727  	   /* assign variables, start and endpoints to arrays */
728  	   for ( j = 0; j < nvars; ++j )
729  	   {
730  	      assert(vars != NULL);
731  	
732  	      var = vars[j];
733  	      assert(var != NULL);
734  	
735  	      if( local )
736  	         starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
737  	      else
738  	         starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
739  	
740  	      startindices[j] = j;
741  	
742  	      if( local )
743  	         endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
744  	      else
745  	         endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
746  	
747  	      endindices[j] = j;
748  	   }
749  	
750  	   /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
751  	   SCIPsortIntInt(starttimes, startindices, j);
752  	   SCIPsortIntInt(endtimes, endindices, j);
753  	}
754  	
755  	/** initialize the sorted event point arrays w.r.t. the given primal solutions */
756  	static
757  	void createSortedEventpointsSol(
758  	   SCIP*                 scip,               /**< SCIP data structure */
759  	   SCIP_SOL*             sol,                /**< solution */
760  	   int                   nvars,              /**< number of start time variables (activities) */
761  	   SCIP_VAR**            vars,               /**< array of start time variables */
762  	   int*                  durations,          /**< array of durations per start time variable */
763  	   int*                  starttimes,         /**< array to store sorted start events */
764  	   int*                  endtimes,           /**< array to store sorted end events */
765  	   int*                  startindices,       /**< permutation with rspect to the start times */
766  	   int*                  endindices          /**< permutation with rspect to the end times */
767  	   )
768  	{
769  	   SCIP_VAR* var;
770  	   int j;
771  	
772  	   assert(vars != NULL || nvars == 0);
773  	
774  	   /* assign variables, start and endpoints to arrays */
775  	   for ( j = 0; j < nvars; ++j )
776  	   {
777  	      assert(vars != NULL);
778  	
779  	      var = vars[j];
780  	      assert(var != NULL);
781  	
782  	      starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
783  	      startindices[j] = j;
784  	
785  	      endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
786  	      endindices[j] = j;
787  	   }
788  	
789  	   /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
790  	   SCIPsortIntInt(starttimes, startindices, j);
791  	   SCIPsortIntInt(endtimes, endindices, j);
792  	}
793  	
794  	/** initialize the sorted event point arrays
795  	 *
796  	 * @todo Check the separation process!
797  	 */
798  	static
799  	void createSelectedSortedEventpointsSol(
800  	   SCIP*                 scip,               /**< SCIP data structure */
801  	   SCIP_CONSDATA*        consdata,           /**< constraint data */
802  	   SCIP_SOL*             sol,                /**< primal CIP solution, NULL for current LP solution */
803  	   int*                  starttimes,         /**< array to store sorted start events */
804  	   int*                  endtimes,           /**< array to store sorted end events */
805  	   int*                  startindices,       /**< permutation with rspect to the start times */
806  	   int*                  endindices,         /**< permutation with rspect to the end times */
807  	   int*                  nvars,              /**< number of variables that are integral */
808  	   SCIP_Bool             lower               /**< shall the constraints be derived for lower or upper bounds? */
809  	   )
810  	{
811  	   SCIP_VAR* var;
812  	   int tmpnvars;
813  	   int j;
814  	
815  	   tmpnvars = consdata->nvars;
816  	   *nvars = 0;
817  	
818  	   /* assign variables, start and endpoints to arrays */
819  	   for ( j = 0; j < tmpnvars; ++j )
820  	   {
821  	      var = consdata->vars[j];
822  	      assert(var != NULL);
823  	      assert(consdata->durations[j] > 0);
824  	      assert(consdata->demands[j] > 0);
825  	
826  	      if( lower )
827  	      {
828  	         /* only consider jobs that are at their lower or upper bound */
829  	         if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
830  	            || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
831  	            continue;
832  	
833  	         starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
834  	         startindices[*nvars] = j;
835  	
836  	         endtimes[*nvars] =  starttimes[*nvars] + consdata->durations[j];
837  	         endindices[*nvars] = j;
838  	
839  	         SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
840  	            *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
841  	            consdata->durations[j],
842  	            starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
843  	            consdata->demands[startindices[*nvars]]);
844  	
845  	         (*nvars)++;
846  	      }
847  	      else
848  	      {
849  	         if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
850  	            || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
851  	            continue;
852  	
853  	         starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
854  	         startindices[*nvars] = j;
855  	
856  	         endtimes[*nvars] =  starttimes[*nvars] + consdata->durations[j];
857  	         endindices[*nvars] = j;
858  	
859  	         SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
860  	            *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
861  	            consdata->durations[j],
862  	            starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
863  	            consdata->demands[startindices[*nvars]]);
864  	
865  	         (*nvars)++;
866  	      }
867  	   }
868  	
869  	   /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
870  	   SCIPsortIntInt(starttimes, startindices, *nvars);
871  	   SCIPsortIntInt(endtimes, endindices, *nvars);
872  	
873  	#ifdef SCIP_DEBUG
874  	   SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
875  	
876  	   for ( j = 0; j < *nvars; ++j )
877  	   {
878  	      SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
879  	         startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
880  	         consdata->demands[startindices[j]]);
881  	   }
882  	
883  	   for ( j = 0; j < *nvars; ++j )
884  	   {
885  	      SCIPdebugMsg(scip, "%d: job[%d] endtime %d,  demand = %d\n", j, endindices[j], endtimes[j],
886  	         consdata->demands[endindices[j]]);
887  	   }
888  	#endif
889  	}
890  	
891  	#ifdef SCIP_STATISTIC
892  	/** this method checks for relevant intervals for energetic reasoning */
893  	static
894  	SCIP_RETCODE computeRelevantEnergyIntervals(
895  	   SCIP*                 scip,               /**< SCIP data structure */
896  	   int                   nvars,              /**< number of start time variables (activities) */
897  	   SCIP_VAR**            vars,               /**< array of start time variables */
898  	   int*                  durations,          /**< array of durations */
899  	   int*                  demands,            /**< array of demands */
900  	   int                   capacity,           /**< cumulative capacity */
901  	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
902  	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
903  	   int**                 timepoints,         /**< array to store relevant points in time */
904  	   SCIP_Real**           cumulativedemands,  /**< array to store the estimated cumulative demand for each point in time */
905  	   int*                  ntimepoints,        /**< pointer to store the number of timepoints */
906  	   int*                  maxdemand,          /**< pointer to store maximum over all demands */
907  	   SCIP_Real*            minfreecapacity     /**< pointer to store the minimum free capacity */
908  	   )
909  	{
910  	   int* starttimes;         /* stores when each job is starting */
911  	   int* endtimes;           /* stores when each job ends */
912  	   int* startindices;       /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
913  	   int* endindices;         /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
914  	
915  	   SCIP_Real totaldemand;
916  	   int curtime;             /* point in time which we are just checking */
917  	   int endindex;            /* index of endsolvalues with: endsolvalues[endindex] > curtime */
918  	
919  	   int j;
920  	
921  	   assert( scip != NULL );
922  	   assert(durations != NULL);
923  	   assert(demands != NULL);
924  	   assert(capacity >= 0);
925  	
926  	   /* if no activities are associated with this cumulative then this constraint is redundant */
927  	   if( nvars == 0 )
928  	      return SCIP_OKAY;
929  	
930  	   assert(vars != NULL);
931  	
932  	   SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
933  	   SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
934  	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
935  	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
936  	
937  	   /* create event point arrays */
938  	   createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
939  	
940  	   endindex = 0;
941  	   totaldemand = 0.0;
942  	
943  	   *ntimepoints = 0;
944  	   (*timepoints)[0] = starttimes[0];
945  	   (*cumulativedemands)[0] = 0;
946  	   *maxdemand = 0;
947  	
948  	   /* check each startpoint of a job whether the capacity is kept or not */
949  	   for( j = 0; j < nvars; ++j )
950  	   {
951  	      int lct;
952  	      int idx;
953  	
954  	      curtime = starttimes[j];
955  	
956  	      if( curtime >= hmax )
957  	         break;
958  	
959  	      /* free all capacity usages of jobs the are no longer running */
960  	      while( endindex < nvars && endtimes[endindex] <= curtime )
961  	      {
962  	         int est;
963  	
964  	         if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
965  	         {
966  	            (*ntimepoints)++;
967  	            (*timepoints)[*ntimepoints] = endtimes[endindex];
968  	            (*cumulativedemands)[*ntimepoints] = 0;
969  	         }
970  	
971  	         idx = endindices[endindex];
972  	         est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
973  	         totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
974  	         endindex++;
975  	
976  	         (*cumulativedemands)[*ntimepoints] = totaldemand;
977  	      }
978  	
979  	      idx = startindices[j];
980  	      lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
981  	      totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
982  	
983  	      if( (*timepoints)[*ntimepoints] < curtime )
984  	      {
985  	         (*ntimepoints)++;
986  	         (*timepoints)[*ntimepoints] = curtime;
987  	         (*cumulativedemands)[*ntimepoints] = 0;
988  	      }
989  	
990  	      (*cumulativedemands)[*ntimepoints] = totaldemand;
991  	
992  	      /* add the relative capacity requirements for all job which start at the curtime */
993  	      while( j+1 < nvars && starttimes[j+1] == curtime )
994  	      {
995  	         ++j;
996  	         idx = startindices[j];
997  	         lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
998  	         totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
999  	
1000 	         (*cumulativedemands)[*ntimepoints] = totaldemand;
1001 	      }
1002 	   } /*lint --e{850}*/
1003 	
1004 	   /* free all capacity usages of jobs that are no longer running */
1005 	   while( endindex < nvars/* && endtimes[endindex] < hmax*/)
1006 	   {
1007 	      int est;
1008 	      int idx;
1009 	
1010 	      if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
1011 	      {
1012 	         (*ntimepoints)++;
1013 	         (*timepoints)[*ntimepoints] = endtimes[endindex];
1014 	         (*cumulativedemands)[*ntimepoints] = 0;
1015 	      }
1016 	
1017 	      idx = endindices[endindex];
1018 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
1019 	      totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1020 	      (*cumulativedemands)[*ntimepoints] = totaldemand;
1021 	
1022 	      ++endindex;
1023 	   }
1024 	
1025 	   (*ntimepoints)++;
1026 	   /* compute minimum free capacity */
1027 	   (*minfreecapacity) = INT_MAX;
1028 	   for( j = 0; j < *ntimepoints; ++j )
1029 	   {
1030 	      if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1031 	         *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1032 	   }
1033 	
1034 	   /* free buffer arrays */
1035 	   SCIPfreeBufferArray(scip, &endindices);
1036 	   SCIPfreeBufferArray(scip, &startindices);
1037 	   SCIPfreeBufferArray(scip, &endtimes);
1038 	   SCIPfreeBufferArray(scip, &starttimes);
1039 	
1040 	   return SCIP_OKAY;
1041 	}
1042 	
1043 	/** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1044 	static
1045 	SCIP_RETCODE evaluateCumulativeness(
1046 	   SCIP*                 scip,               /**< pointer to scip */
1047 	   SCIP_CONS*            cons                /**< cumulative constraint */
1048 	   )
1049 	{
1050 	   SCIP_CONSDATA* consdata;
1051 	   int nvars;
1052 	   int v;
1053 	   int capacity;
1054 	
1055 	   /* output values: */
1056 	   SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1057 	   SCIP_Real cumfactor1;
1058 	   SCIP_Real resstrength1; /* overall strength */
1059 	   SCIP_Real resstrength2; /* timepoint wise maximum */
1060 	
1061 	   /* helpful variables: */
1062 	   SCIP_Real globalpeak;
1063 	   SCIP_Real globalmaxdemand;
1064 	
1065 	   /* get constraint data structure */
1066 	   consdata = SCIPconsGetData(cons);
1067 	   assert(consdata != NULL);
1068 	
1069 	   nvars = consdata->nvars;
1070 	   capacity = consdata->capacity;
1071 	   globalpeak = 0.0;
1072 	   globalmaxdemand = 0.0;
1073 	
1074 	   disjfactor2 = 0.0;
1075 	   cumfactor1 = 0.0;
1076 	   resstrength2 = 0.0;
1077 	
1078 	   /* check each starting time (==each job, but inefficient) */
1079 	   for( v = 0; v < nvars; ++v )
1080 	   {
1081 	      SCIP_Real peak;
1082 	      SCIP_Real maxdemand;
1083 	      SCIP_Real deltademand;
1084 	      int ndemands;
1085 	      int nlarge;
1086 	
1087 	      int timepoint;
1088 	      int j;
1089 	      timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1090 	      peak = consdata->demands[v];
1091 	      ndemands = 1;
1092 	      maxdemand = 0;
1093 	      nlarge = 0;
1094 	
1095 	      if( consdata->demands[v] > capacity / 3 )
1096 	         nlarge++;
1097 	
1098 	      for( j = 0; j < nvars; ++j )
1099 	      {
1100 	         int lb;
1101 	
1102 	         if( j == v )
1103 	            continue;
1104 	
1105 	         maxdemand = 0.0;
1106 	         lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1107 	
1108 	         if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1109 	         {
1110 	            peak += consdata->demands[j];
1111 	            ndemands++;
1112 	
1113 	            if( consdata->demands[j] > consdata->capacity / 3 )
1114 	               nlarge++;
1115 	         }
1116 	      }
1117 	
1118 	      deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1119 	      globalpeak = MAX(globalpeak, peak);
1120 	      globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1121 	
1122 	      if( peak > capacity )
1123 	      {
1124 	         disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1125 	         cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1126 	         resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1127 	      }
1128 	   }
1129 	
1130 	   resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1131 	
1132 	   consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1133 	   consdata->disjfactor2 = disjfactor2;
1134 	   consdata->cumfactor1 = cumfactor1;
1135 	   consdata->resstrength2 = resstrength2;
1136 	   consdata->resstrength1 = resstrength1;
1137 	
1138 	   /* get estimated res strength */
1139 	   {
1140 	      int* timepoints;
1141 	      SCIP_Real* estimateddemands;
1142 	      int ntimepoints;
1143 	      int maxdemand;
1144 	      SCIP_Real minfreecapacity;
1145 	
1146 	      SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1147 	      SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1148 	
1149 	      ntimepoints = 0;
1150 	      minfreecapacity = INT_MAX;
1151 	
1152 	      SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1153 	            consdata->durations, consdata->demands,
1154 	            capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1155 	            &ntimepoints, &maxdemand, &minfreecapacity) );
1156 	
1157 	      /* free buffer arrays */
1158 	      SCIPfreeBufferArray(scip, &estimateddemands);
1159 	      SCIPfreeBufferArray(scip, &timepoints);
1160 	
1161 	      consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1162 	   }
1163 	
1164 	   SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1165 	      SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1166 	      consdata->estimatedstrength);
1167 	
1168 	   return SCIP_OKAY;
1169 	}
1170 	#endif
1171 	
1172 	/** gets the active variables together with the constant */
1173 	static
1174 	SCIP_RETCODE getActiveVar(
1175 	   SCIP*                 scip,               /**< SCIP data structure */
1176 	   SCIP_VAR**            var,                /**< pointer to store the active variable */
1177 	   int*                  scalar,             /**< pointer to store the scalar */
1178 	   int*                  constant            /**< pointer to store the constant */
1179 	   )
1180 	{
1181 	   if( !SCIPvarIsActive(*var) )
1182 	   {
1183 	      SCIP_Real realscalar;
1184 	      SCIP_Real realconstant;
1185 	
1186 	      realscalar = 1.0;
1187 	      realconstant = 0.0;
1188 	
1189 	      assert(SCIPvarGetStatus(*var) == SCIP_VARSTATUS_AGGREGATED);
1190 	
1191 	      /* transform variable to active variable */
1192 	      SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1193 	      assert(!SCIPisZero(scip, realscalar));
1194 	      assert(SCIPvarIsActive(*var));
1195 	
1196 	      if( realconstant < 0.0 )
1197 	         (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1198 	      else
1199 	         (*constant) = SCIPconvertRealToInt(scip, realconstant);
1200 	
1201 	      if( realscalar < 0.0 )
1202 	         (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1203 	      else
1204 	         (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1205 	   }
1206 	   else
1207 	   {
1208 	      (*scalar) = 1;
1209 	      (*constant) = 0;
1210 	   }
1211 	
1212 	   assert(*scalar != 0);
1213 	
1214 	   return SCIP_OKAY;
1215 	}
1216 	
1217 	/** computes the total energy of all jobs */
1218 	static
1219 	SCIP_Longint computeTotalEnergy(
1220 	   int*                  durations,          /**< array of job durations */
1221 	   int*                  demands,            /**< array of job demands */
1222 	   int                   njobs               /**< number of jobs */
1223 	   )
1224 	{
1225 	   SCIP_Longint energy;
1226 	   int j;
1227 	
1228 	   energy = 0;
1229 	
1230 	   for( j = 0; j < njobs; ++j )
1231 	      energy += (SCIP_Longint) durations[j] * demands[j];
1232 	
1233 	   return energy;
1234 	}
1235 	
1236 	/**@} */
1237 	
1238 	/**@name Default method to solve a cumulative condition
1239 	 *
1240 	 * @{
1241 	 */
1242 	
1243 	/** setup and solve subscip to solve single cumulative condition  */
1244 	static
1245 	SCIP_RETCODE setupAndSolveCumulativeSubscip(
1246 	   SCIP*                 subscip,            /**< subscip data structure */
1247 	   SCIP_Real*            objvals,            /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1248 	   int*                  durations,          /**< array of durations */
1249 	   int*                  demands,            /**< array of demands */
1250 	   int                   njobs,              /**< number of jobs (activities) */
1251 	   int                   capacity,           /**< cumulative capacity */
1252 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
1253 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
1254 	   SCIP_Longint          maxnodes,           /**< maximum number of branch-and-bound nodes (-1: no limit) */
1255 	   SCIP_Real             timelimit,          /**< time limit for solving in seconds */
1256 	   SCIP_Real             memorylimit,        /**< memory limit for solving in mega bytes (MB) */
1257 	   SCIP_Real*            ests,               /**< array of earliest start times for each job */
1258 	   SCIP_Real*            lsts,               /**< array of latest start times for each job */
1259 	   SCIP_Bool*            infeasible,         /**< pointer to store if the subproblem was infeasible */
1260 	   SCIP_Bool*            unbounded,          /**< pointer to store if the problem is unbounded */
1261 	   SCIP_Bool*            solved,             /**< pointer to store if the problem is solved (to optimality) */
1262 	   SCIP_Bool*            error               /**< pointer to store if an error occurred */
1263 	   )
1264 	{
1265 	   SCIP_VAR** subvars;
1266 	   SCIP_CONS* cons;
1267 	
1268 	   char name[SCIP_MAXSTRLEN];
1269 	   int v;
1270 	   SCIP_RETCODE retcode;
1271 	
1272 	   assert(subscip != NULL);
1273 	
1274 	   /* copy all plugins */
1275 	   SCIP_CALL( SCIPincludeDefaultPlugins(subscip) );
1276 	
1277 	   /* create the subproblem */
1278 	   SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1279 	
1280 	   SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1281 	
1282 	   /* create for each job a start time variable */
1283 	   for( v = 0; v < njobs; ++v )
1284 	   {
1285 	      SCIP_Real objval;
1286 	
1287 	      /* construct variable name */
1288 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1289 	
1290 	      if( objvals == NULL )
1291 	         objval = 0.0;
1292 	      else
1293 	         objval = objvals[v];
1294 	
1295 	      SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1296 	      SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1297 	   }
1298 	
1299 	   /* create cumulative constraint */
1300 	   SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1301 	         njobs, subvars, durations, demands, capacity) );
1302 	
1303 	   /* set effective horizon */
1304 	   SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1305 	   SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1306 	
1307 	   /* add cumulative constraint */
1308 	   SCIP_CALL( SCIPaddCons(subscip, cons) );
1309 	   SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1310 	
1311 	   /* set CP solver settings
1312 	    *
1313 	    * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1314 	    *       time limit.
1315 	    */
1316 	   SCIP_CALL( SCIPsetEmphasis(subscip, SCIP_PARAMEMPHASIS_CPSOLVER, TRUE) );
1317 	
1318 	   /* do not abort subproblem on CTRL-C */
1319 	   SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1320 	
1321 	   /* disable output to console */
1322 	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1323 	
1324 	   /* set limits for the subproblem */
1325 	   SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1326 	   SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1327 	   SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1328 	
1329 	   /* forbid recursive call of heuristics and separators solving subMIPs */
1330 	   SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1331 	
1332 	   /* solve single cumulative constraint by branch and bound */
1333 	   retcode = SCIPsolve(subscip);
1334 	
1335 	   if( retcode != SCIP_OKAY )
1336 	      (*error) = TRUE;
1337 	   else
1338 	   {
1339 	      SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1340 	
1341 	      /* evaluated solution status */
1342 	      switch( SCIPgetStatus(subscip) )
1343 	      {
1344 	      case SCIP_STATUS_INFORUNBD:
1345 	      case SCIP_STATUS_INFEASIBLE:
1346 	         (*infeasible) = TRUE;
1347 	         (*solved) = TRUE;
1348 	         break;
1349 	      case SCIP_STATUS_UNBOUNDED:
1350 	         (*unbounded) = TRUE;
1351 	         (*solved) = TRUE;
1352 	         break;
1353 	      case SCIP_STATUS_OPTIMAL:
1354 	      {
1355 	         SCIP_SOL* sol;
1356 	         SCIP_Real solval;
1357 	
1358 	         sol = SCIPgetBestSol(subscip);
1359 	         assert(sol != NULL);
1360 	
1361 	         for( v = 0; v < njobs; ++v )
1362 	         {
1363 	            solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1364 	
1365 	            ests[v] = solval;
1366 	            lsts[v] = solval;
1367 	         }
1368 	         (*solved) = TRUE;
1369 	         break;
1370 	      }
1371 	      case SCIP_STATUS_NODELIMIT:
1372 	      case SCIP_STATUS_TOTALNODELIMIT:
1373 	      case SCIP_STATUS_TIMELIMIT:
1374 	      case SCIP_STATUS_MEMLIMIT:
1375 	      case SCIP_STATUS_USERINTERRUPT:
1376 	      case SCIP_STATUS_TERMINATE:
1377 	         /* transfer the global bound changes */
1378 	         for( v = 0; v < njobs; ++v )
1379 	         {
1380 	            ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1381 	            lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1382 	         }
1383 	         (*solved) = FALSE;
1384 	         break;
1385 	
1386 	      case SCIP_STATUS_UNKNOWN:
1387 	      case SCIP_STATUS_STALLNODELIMIT:
1388 	      case SCIP_STATUS_GAPLIMIT:
1389 	      case SCIP_STATUS_SOLLIMIT:
1390 	      case SCIP_STATUS_BESTSOLLIMIT:
1391 	      case SCIP_STATUS_RESTARTLIMIT:
1392 	         SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1393 	         return SCIP_INVALIDDATA;
1394 	      }
1395 	   }
1396 	
1397 	   /* release all variables */
1398 	   for( v = 0; v < njobs; ++v )
1399 	   {
1400 	      SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1401 	   }
1402 	
1403 	   SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1404 	
1405 	   return SCIP_OKAY;
1406 	}
1407 	
1408 	/** solve single cumulative condition using SCIP and a single cumulative constraint */
1409 	static
1410 	SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1411 	{
1412 	   SCIP* subscip;
1413 	
1414 	   SCIP_RETCODE retcode;
1415 	
1416 	   assert(njobs > 0);
1417 	
1418 	   (*solved) = FALSE;
1419 	   (*infeasible) = FALSE;
1420 	   (*unbounded) = FALSE;
1421 	   (*error) = FALSE;
1422 	
1423 	   SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1424 	
1425 	   /* initialize the sub-problem */
1426 	   SCIP_CALL( SCIPcreate(&subscip) );
1427 	
1428 	   /* create and solve the subproblem. catch possible errors */
1429 	   retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1430 	         njobs, capacity, hmin, hmax,
1431 	         maxnodes, timelimit, memorylimit,
1432 	         ests, lsts,
1433 	         infeasible, unbounded, solved, error);
1434 	
1435 	   /* free the subscip in any case */
1436 	   SCIP_CALL( SCIPfree(&subscip) );
1437 	
1438 	   SCIP_CALL( retcode );
1439 	
1440 	   return SCIP_OKAY;
1441 	}
1442 	
1443 	#if 0
1444 	/** solve single cumulative condition using SCIP and the time indexed formulation */
1445 	static
1446 	SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1447 	{
1448 	   SCIP* subscip;
1449 	   SCIP_VAR*** binvars;
1450 	   SCIP_RETCODE retcode;
1451 	   char name[SCIP_MAXSTRLEN];
1452 	   int minest;
1453 	   int maxlct;
1454 	   int t;
1455 	   int v;
1456 	
1457 	   assert(njobs > 0);
1458 	
1459 	   (*solved) = FALSE;
1460 	   (*infeasible) = FALSE;
1461 	   (*unbounded) = FALSE;
1462 	   (*error) = FALSE;
1463 	
1464 	   SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1465 	
1466 	   /* initialize the sub-problem */
1467 	   SCIP_CALL( SCIPcreate(&subscip) );
1468 	
1469 	   /* copy all plugins */
1470 	   SCIP_CALL( SCIPincludeDefaultPlugins(subscip) );
1471 	
1472 	   /* create the subproblem */
1473 	   SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1474 	
1475 	   SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1476 	
1477 	   minest = INT_MAX;
1478 	   maxlct = INT_MIN;
1479 	
1480 	   /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1481 	    * partitioning constrain which forces that job starts
1482 	    */
1483 	   for( v = 0; v < njobs; ++v )
1484 	   {
1485 	      SCIP_CONS* cons;
1486 	      SCIP_Real objval;
1487 	      int timeinterval;
1488 	      int est;
1489 	      int lst;
1490 	
1491 	      if( objvals == NULL )
1492 	         objval = 0.0;
1493 	      else
1494 	         objval = objvals[v];
1495 	
1496 	      est = ests[v];
1497 	      lst = lsts[v];
1498 	
1499 	      /* compute number of possible start points */
1500 	      timeinterval = lst - est + 1;
1501 	      assert(timeinterval > 0);
1502 	
1503 	      /* compute the smallest earliest start time and largest latest completion time */
1504 	      minest = MIN(minest, est);
1505 	      maxlct = MAX(maxlct, lst + durations[v]);
1506 	
1507 	      /* construct constraint name */
1508 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1509 	
1510 	      SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1511 	
1512 	      SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1513 	
1514 	      for( t = 0; t < timeinterval; ++t )
1515 	      {
1516 	         SCIP_VAR* binvar;
1517 	
1518 	         /* construct varibale name */
1519 	         (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1520 	
1521 	         SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1522 	         SCIP_CALL( SCIPaddVar(subscip, binvar) );
1523 	
1524 	         /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1525 	         SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1526 	
1527 	         binvars[v][t] = binvar;
1528 	      }
1529 	
1530 	      /* add and release the set partitioning constraint */
1531 	      SCIP_CALL( SCIPaddCons(subscip, cons) );
1532 	      SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1533 	   }
1534 	
1535 	   /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1536 	   hmin = MAX(hmin, minest);
1537 	   hmax = MIN(hmax, maxlct);
1538 	   assert(hmin > INT_MIN);
1539 	   assert(hmax < INT_MAX);
1540 	   assert(hmin < hmax);
1541 	
1542 	   /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1543 	   for( t = hmin; t < hmax; ++t )
1544 	   {
1545 	      SCIP_CONS* cons;
1546 	
1547 	      /* construct constraint name */
1548 	      (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1549 	
1550 	      /* create an empty knapsack constraint */
1551 	      SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1552 	
1553 	      /* add all jobs which potentially can be processed at that time point */
1554 	      for( v = 0; v < njobs; ++v )
1555 	      {
1556 	         int duration;
1557 	         int demand;
1558 	         int start;
1559 	         int end;
1560 	         int est;
1561 	         int lst;
1562 	         int k;
1563 	
1564 	         est = ests[v];
1565 	         lst = lsts[v] ;
1566 	
1567 	         duration = durations[v];
1568 	         assert(duration > 0);
1569 	
1570 	         /* check if the varibale is processed potentially at time point t */
1571 	         if( t < est || t >= lst + duration )
1572 	            continue;
1573 	
1574 	         demand = demands[v];
1575 	         assert(demand >= 0);
1576 	
1577 	         start = MAX(t - duration + 1, est);
1578 	         end = MIN(t, lst);
1579 	
1580 	         assert(start <= end);
1581 	
1582 	         for( k = start; k <= end; ++k )
1583 	         {
1584 	            assert(binvars[v][k] != NULL);
1585 	            SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1586 	         }
1587 	      }
1588 	
1589 	      /* add and release the knapsack constraint */
1590 	      SCIP_CALL( SCIPaddCons(subscip, cons) );
1591 	      SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1592 	   }
1593 	
1594 	   /* do not abort subproblem on CTRL-C */
1595 	   SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1596 	
1597 	   /* disable output to console */
1598 	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1599 	
1600 	   /* set limits for the subproblem */
1601 	   SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1602 	   SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1603 	   SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1604 	
1605 	   /* solve single cumulative constraint by branch and bound */
1606 	   retcode = SCIPsolve(subscip);
1607 	
1608 	   if( retcode != SCIP_OKAY )
1609 	      (*error) = TRUE;
1610 	   else
1611 	   {
1612 	      SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1613 	
1614 	      /* evaluated solution status */
1615 	      switch( SCIPgetStatus(subscip) )
1616 	      {
1617 	      case SCIP_STATUS_INFORUNBD:
1618 	      case SCIP_STATUS_INFEASIBLE:
1619 	         (*infeasible) = TRUE;
1620 	         (*solved) = TRUE;
1621 	         break;
1622 	      case SCIP_STATUS_UNBOUNDED:
1623 	         (*unbounded) = TRUE;
1624 	         (*solved) = TRUE;
1625 	         break;
1626 	      case SCIP_STATUS_OPTIMAL:
1627 	      {
1628 	         SCIP_SOL* sol;
1629 	
1630 	         sol = SCIPgetBestSol(subscip);
1631 	         assert(sol != NULL);
1632 	
1633 	         for( v = 0; v < njobs; ++v )
1634 	         {
1635 	            int timeinterval;
1636 	            int est;
1637 	            int lst;
1638 	
1639 	            est = ests[v];
1640 	            lst = lsts[v];
1641 	
1642 	            /* compute number of possible start points */
1643 	            timeinterval = lst - est + 1;
1644 	
1645 	            /* check which binary varibale is set to one */
1646 	            for( t = 0; t < timeinterval; ++t )
1647 	            {
1648 	               if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1649 	               {
1650 	                  ests[v] = est + t;
1651 	                  lsts[v] = est + t;
1652 	                  break;
1653 	               }
1654 	            }
1655 	         }
1656 	
1657 	         (*solved) = TRUE;
1658 	         break;
1659 	      }
1660 	      case SCIP_STATUS_NODELIMIT:
1661 	      case SCIP_STATUS_TOTALNODELIMIT:
1662 	      case SCIP_STATUS_TIMELIMIT:
1663 	      case SCIP_STATUS_MEMLIMIT:
1664 	      case SCIP_STATUS_USERINTERRUPT:
1665 	         /* transfer the global bound changes */
1666 	         for( v = 0; v < njobs; ++v )
1667 	         {
1668 	            int timeinterval;
1669 	            int est;
1670 	            int lst;
1671 	
1672 	            est = ests[v];
1673 	            lst = lsts[v];
1674 	
1675 	            /* compute number of possible start points */
1676 	            timeinterval = lst - est + 1;
1677 	
1678 	            /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1679 	            for( t = 0; t < timeinterval; ++t )
1680 	            {
1681 	               if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1682 	               {
1683 	                  ests[v] = est + t;
1684 	                  break;
1685 	               }
1686 	            }
1687 	
1688 	            /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1689 	            for( t = timeinterval - 1; t >= 0; --t )
1690 	            {
1691 	               if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1692 	               {
1693 	                  lsts[v] = est + t;
1694 	                  break;
1695 	               }
1696 	            }
1697 	         }
1698 	         (*solved) = FALSE;
1699 	         break;
1700 	
1701 	      case SCIP_STATUS_UNKNOWN:
1702 	      case SCIP_STATUS_STALLNODELIMIT:
1703 	      case SCIP_STATUS_GAPLIMIT:
1704 	      case SCIP_STATUS_SOLLIMIT:
1705 	      case SCIP_STATUS_BESTSOLLIMIT:
1706 	         SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1707 	         return SCIP_INVALIDDATA;
1708 	      }
1709 	   }
1710 	
1711 	   /* release all variables */
1712 	   for( v = 0; v < njobs; ++v )
1713 	   {
1714 	      int timeinterval;
1715 	      int est;
1716 	      int lst;
1717 	
1718 	      est = ests[v];
1719 	      lst = lsts[v];
1720 	
1721 	      /* compute number of possible start points */
1722 	      timeinterval = lst - est + 1;
1723 	
1724 	      for( t = 0; t < timeinterval; ++t )
1725 	      {
1726 	         SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1727 	      }
1728 	      SCIPfreeBufferArray(subscip, &binvars[v]);
1729 	   }
1730 	
1731 	   SCIPfreeBufferArray(subscip, &binvars);
1732 	
1733 	   SCIP_CALL( SCIPfree(&subscip) );
1734 	
1735 	   return SCIP_OKAY;
1736 	}
1737 	#endif
1738 	
1739 	/**@} */
1740 	
1741 	/**@name Constraint handler data
1742 	 *
1743 	 * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1744 	 * handler.
1745 	 *
1746 	 * @{
1747 	 */
1748 	
1749 	/** creates constaint handler data for cumulative constraint handler */
1750 	static
1751 	SCIP_RETCODE conshdlrdataCreate(
1752 	   SCIP*                 scip,               /**< SCIP data structure */
1753 	   SCIP_CONSHDLRDATA**   conshdlrdata,       /**< pointer to store the constraint handler data */
1754 	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler */
1755 	   )
1756 	{
1757 	   /* create precedence constraint handler data */
1758 	   assert(scip != NULL);
1759 	   assert(conshdlrdata != NULL);
1760 	   assert(eventhdlr != NULL);
1761 	
1762 	   SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1763 	
1764 	   /* set event handler for checking if bounds of start time variables are tighten */
1765 	   (*conshdlrdata)->eventhdlr = eventhdlr;
1766 	
1767 	   /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1768 	   (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1769 	
1770 	#ifdef SCIP_STATISTIC
1771 	   (*conshdlrdata)->nlbtimetable = 0;
1772 	   (*conshdlrdata)->nubtimetable = 0;
1773 	   (*conshdlrdata)->ncutofftimetable = 0;
1774 	   (*conshdlrdata)->nlbedgefinder = 0;
1775 	   (*conshdlrdata)->nubedgefinder = 0;
1776 	   (*conshdlrdata)->ncutoffedgefinder = 0;
1777 	   (*conshdlrdata)->ncutoffoverload = 0;
1778 	   (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1779 	
1780 	   (*conshdlrdata)->nirrelevantjobs = 0;
1781 	   (*conshdlrdata)->nalwaysruns = 0;
1782 	   (*conshdlrdata)->nremovedlocks = 0;
1783 	   (*conshdlrdata)->ndualfixs = 0;
1784 	   (*conshdlrdata)->ndecomps = 0;
1785 	   (*conshdlrdata)->ndualbranchs = 0;
1786 	   (*conshdlrdata)->nallconsdualfixs = 0;
1787 	   (*conshdlrdata)->naddedvarbounds = 0;
1788 	   (*conshdlrdata)->naddeddisjunctives = 0;
1789 	#endif
1790 	
1791 	   return SCIP_OKAY;
1792 	}
1793 	
1794 	/** frees constraint handler data for logic or constraint handler */
1795 	static
1796 	void conshdlrdataFree(
1797 	   SCIP*                 scip,               /**< SCIP data structure */
1798 	   SCIP_CONSHDLRDATA**   conshdlrdata        /**< pointer to the constraint handler data */
1799 	   )
1800 	{
1801 	   assert(conshdlrdata != NULL);
1802 	   assert(*conshdlrdata != NULL);
1803 	
1804 	   SCIPfreeBlockMemory(scip, conshdlrdata);
1805 	}
1806 	
1807 	/**@} */
1808 	
1809 	
1810 	/**@name Constraint data methods
1811 	 *
1812 	 * @{
1813 	 */
1814 	
1815 	/** catches bound change events for all variables in transformed cumulative constraint */
1816 	static
1817 	SCIP_RETCODE consdataCatchEvents(
1818 	   SCIP*                 scip,               /**< SCIP data structure */
1819 	   SCIP_CONSDATA*        consdata,           /**< cumulative constraint data */
1820 	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
1821 	   )
1822 	{
1823 	   int v;
1824 	
1825 	   assert(scip != NULL);
1826 	   assert(consdata != NULL);
1827 	   assert(eventhdlr != NULL);
1828 	
1829 	   /* catch event for every single variable */
1830 	   for( v = 0; v < consdata->nvars; ++v )
1831 	   {
1832 	      SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1833 	            SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1834 	   }
1835 	
1836 	   return SCIP_OKAY;
1837 	}
1838 	
1839 	/** drops events for variable at given position */
1840 	static
1841 	SCIP_RETCODE consdataDropEvents(
1842 	   SCIP*                 scip,               /**< SCIP data structure */
1843 	   SCIP_CONSDATA*        consdata,           /**< cumulative constraint data */
1844 	   SCIP_EVENTHDLR*       eventhdlr,          /**< event handler to call for the event processing */
1845 	   int                   pos                 /**< array position of variable to catch bound change events for */
1846 	   )
1847 	{
1848 	   assert(scip != NULL);
1849 	   assert(consdata != NULL);
1850 	   assert(eventhdlr != NULL);
1851 	   assert(0 <= pos && pos < consdata->nvars);
1852 	   assert(consdata->vars[pos] != NULL);
1853 	
1854 	   SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1855 	         SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1856 	
1857 	   return SCIP_OKAY;
1858 	}
1859 	
1860 	/** drops bound change events for all variables in transformed linear constraint */
1861 	static
1862 	SCIP_RETCODE consdataDropAllEvents(
1863 	   SCIP*                 scip,               /**< SCIP data structure */
1864 	   SCIP_CONSDATA*        consdata,           /**< linear constraint data */
1865 	   SCIP_EVENTHDLR*       eventhdlr           /**< event handler to call for the event processing */
1866 	   )
1867 	{
1868 	   int v;
1869 	
1870 	   assert(scip != NULL);
1871 	   assert(consdata != NULL);
1872 	
1873 	   /* drop event of every single variable */
1874 	   for( v = 0; v < consdata->nvars; ++v )
1875 	   {
1876 	      SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1877 	   }
1878 	
1879 	   return SCIP_OKAY;
1880 	}
1881 	
1882 	/** initialize variable lock data structure */
1883 	static
1884 	void initializeLocks(
1885 	   SCIP_CONSDATA*        consdata,           /**< constraint data */
1886 	   SCIP_Bool             locked              /**< should the variable be locked? */
1887 	   )
1888 	{
1889 	   int nvars;
1890 	   int v;
1891 	
1892 	   nvars = consdata->nvars;
1893 	
1894 	   /* initialize locking arrays */
1895 	   for( v = 0; v < nvars; ++v )
1896 	   {
1897 	      consdata->downlocks[v] = locked;
1898 	      consdata->uplocks[v] = locked;
1899 	   }
1900 	}
1901 	
1902 	/** creates constraint data of cumulative constraint */
1903 	static
1904 	SCIP_RETCODE consdataCreate(
1905 	   SCIP*                 scip,               /**< SCIP data structure */
1906 	   SCIP_CONSDATA**       consdata,           /**< pointer to consdata */
1907 	   SCIP_VAR**            vars,               /**< array of integer variables */
1908 	   SCIP_CONS**           linkingconss,       /**< array of linking constraints for the integer variables, or NULL */
1909 	   int*                  durations,          /**< array containing corresponding durations */
1910 	   int*                  demands,            /**< array containing corresponding demands */
1911 	   int                   nvars,              /**< number of variables */
1912 	   int                   capacity,           /**< available cumulative capacity */
1913 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
1914 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
1915 	   SCIP_Bool             check               /**< is the corresponding constraint a check constraint */
1916 	   )
1917 	{
1918 	   int v;
1919 	
1920 	   assert(scip != NULL);
1921 	   assert(consdata != NULL);
1922 	   assert(vars != NULL || nvars > 0);
1923 	   assert(demands != NULL);
1924 	   assert(durations != NULL);
1925 	   assert(capacity >= 0);
1926 	   assert(hmin >= 0);
1927 	   assert(hmin < hmax);
1928 	
1929 	   /* create constraint data */
1930 	   SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1931 	
1932 	   (*consdata)->hmin = hmin;
1933 	   (*consdata)->hmax = hmax;
1934 	
1935 	   (*consdata)->capacity = capacity;
1936 	   (*consdata)->demandrows = NULL;
1937 	   (*consdata)->demandrowssize = 0;
1938 	   (*consdata)->ndemandrows = 0;
1939 	   (*consdata)->scoverrows = NULL;
1940 	   (*consdata)->nscoverrows = 0;
1941 	   (*consdata)->scoverrowssize = 0;
1942 	   (*consdata)->bcoverrows = NULL;
1943 	   (*consdata)->nbcoverrows = 0;
1944 	   (*consdata)->bcoverrowssize = 0;
1945 	   (*consdata)->nvars = nvars;
1946 	   (*consdata)->varssize = nvars;
1947 	   (*consdata)->signature = 0;
1948 	   (*consdata)->validsignature = FALSE;
1949 	   (*consdata)->normalized = FALSE;
1950 	   (*consdata)->covercuts = FALSE;
1951 	   (*consdata)->propagated = FALSE;
1952 	   (*consdata)->varbounds = FALSE;
1953 	   (*consdata)->triedsolving = FALSE;
1954 	
1955 	   if( nvars > 0 )
1956 	   {
1957 	      assert(vars != NULL); /* for flexelint */
1958 	
1959 	      SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1960 	      SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1961 	      SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1962 	      (*consdata)->linkingconss = NULL;
1963 	
1964 	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1965 	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1966 	
1967 	      /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
1968 	      initializeLocks(*consdata, check);
1969 	
1970 	      if( linkingconss != NULL )
1971 	      {
1972 	         SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1973 	      }
1974 	
1975 	      /* transform variables, if they are not yet transformed */
1976 	      if( SCIPisTransformed(scip) )
1977 	      {
1978 	         SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1979 	
1980 	         /* get transformed variables and do NOT captures these */
1981 	         SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1982 	
1983 	         /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1984 	          * been multi-aggregated
1985 	          */
1986 	         for( v = 0; v < nvars; ++v )
1987 	         {
1988 	            SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1989 	         }
1990 	
1991 	         if( linkingconss != NULL )
1992 	         {
1993 	            /* get transformed constraints and captures these */
1994 	            SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1995 	
1996 	            for( v = 0; v < nvars; ++v )
1997 	               assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1998 	         }
1999 	      }
2000 	
2001 	#ifndef NDEBUG
2002 	      /* only binary and integer variables can be used in cumulative constraints
2003 	       * for fractional variable values, the constraint cannot be checked
2004 	       */
2005 	      for( v = 0; v < (*consdata)->nvars; ++v )
2006 	         assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2007 	#endif
2008 	   }
2009 	   else
2010 	   {
2011 	      (*consdata)->vars = NULL;
2012 	      (*consdata)->downlocks = NULL;
2013 	      (*consdata)->uplocks = NULL;
2014 	      (*consdata)->demands = NULL;
2015 	      (*consdata)->durations = NULL;
2016 	      (*consdata)->linkingconss = NULL;
2017 	   }
2018 	
2019 	   /* initialize values for running propagation algorithms efficiently */
2020 	   (*consdata)->resstrength1 = -1.0;
2021 	   (*consdata)->resstrength2 = -1.0;
2022 	   (*consdata)->cumfactor1 = -1.0;
2023 	   (*consdata)->disjfactor1 = -1.0;
2024 	   (*consdata)->disjfactor2 = -1.0;
2025 	   (*consdata)->estimatedstrength = -1.0;
2026 	
2027 	   SCIPstatistic( (*consdata)->maxpeak = -1 );
2028 	
2029 	   return SCIP_OKAY;
2030 	}
2031 	
2032 	/** releases LP rows of constraint data and frees rows array */
2033 	static
2034 	SCIP_RETCODE consdataFreeRows(
2035 	   SCIP*                 scip,               /**< SCIP data structure */
2036 	   SCIP_CONSDATA**       consdata            /**< constraint data */
2037 	   )
2038 	{
2039 	   int r;
2040 	
2041 	   assert(consdata != NULL);
2042 	   assert(*consdata != NULL);
2043 	
2044 	   for( r = 0; r < (*consdata)->ndemandrows; ++r )
2045 	   {
2046 	      assert((*consdata)->demandrows[r] != NULL);
2047 	      SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2048 	   }
2049 	
2050 	   SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2051 	
2052 	   (*consdata)->ndemandrows = 0;
2053 	   (*consdata)->demandrowssize = 0;
2054 	
2055 	   /* free rows of cover cuts */
2056 	   for( r = 0; r < (*consdata)->nscoverrows; ++r )
2057 	   {
2058 	      assert((*consdata)->scoverrows[r] != NULL);
2059 	      SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2060 	   }
2061 	
2062 	   SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2063 	
2064 	   (*consdata)->nscoverrows = 0;
2065 	   (*consdata)->scoverrowssize = 0;
2066 	
2067 	   for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2068 	   {
2069 	      assert((*consdata)->bcoverrows[r] != NULL);
2070 	      SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2071 	   }
2072 	
2073 	   SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2074 	
2075 	   (*consdata)->nbcoverrows = 0;
2076 	   (*consdata)->bcoverrowssize = 0;
2077 	
2078 	   (*consdata)->covercuts = FALSE;
2079 	
2080 	   return SCIP_OKAY;
2081 	}
2082 	
2083 	/** frees a cumulative constraint data */
2084 	static
2085 	SCIP_RETCODE consdataFree(
2086 	   SCIP*                 scip,               /**< SCIP data structure */
2087 	   SCIP_CONSDATA**       consdata            /**< pointer to linear constraint data */
2088 	   )
2089 	{
2090 	   int varssize;
2091 	   int nvars;
2092 	
2093 	   assert(consdata != NULL);
2094 	   assert(*consdata != NULL);
2095 	
2096 	   nvars =  (*consdata)->nvars;
2097 	   varssize = (*consdata)->varssize;
2098 	
2099 	   if( varssize > 0 )
2100 	   {
2101 	      int v;
2102 	
2103 	      /* release and free the rows */
2104 	      SCIP_CALL( consdataFreeRows(scip, consdata) );
2105 	
2106 	      /* release the linking constraints if they were generated */
2107 	      if( (*consdata)->linkingconss != NULL )
2108 	      {
2109 	         for( v = nvars-1; v >= 0; --v )
2110 	         {
2111 	            assert((*consdata)->linkingconss[v] != NULL );
2112 	            SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2113 	         }
2114 	
2115 	         SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2116 	      }
2117 	
2118 	      /* free arrays */
2119 	      SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2120 	      SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2121 	      SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2122 	      SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2123 	      SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2124 	   }
2125 	
2126 	   /* free memory */
2127 	   SCIPfreeBlockMemory(scip, consdata);
2128 	
2129 	   return SCIP_OKAY;
2130 	}
2131 	
2132 	/** prints cumulative constraint to file stream */
2133 	static
2134 	void consdataPrint(
2135 	   SCIP*                 scip,               /**< SCIP data structure */
2136 	   SCIP_CONSDATA*        consdata,           /**< cumulative constraint data */
2137 	   FILE*                 file                /**< output file (or NULL for standard output) */
2138 	   )
2139 	{
2140 	   int v;
2141 	
2142 	   assert(consdata != NULL);
2143 	
2144 	   /* print coefficients */
2145 	   SCIPinfoMessage( scip, file, "cumulative(");
2146 	
2147 	   for( v = 0; v < consdata->nvars; ++v )
2148 	   {
2149 	      assert(consdata->vars[v] != NULL);
2150 	      if( v > 0 )
2151 	         SCIPinfoMessage(scip, file, ", ");
2152 	      SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2153 	         SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2154 	         consdata->durations[v], consdata->demands[v]);
2155 	   }
2156 	   SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2157 	}
2158 	
2159 	/** deletes coefficient at given position from constraint data */
2160 	static
2161 	SCIP_RETCODE consdataDeletePos(
2162 	   SCIP*                 scip,               /**< SCIP data structure */
2163 	   SCIP_CONSDATA*        consdata,           /**< cumulative constraint data */
2164 	   SCIP_CONS*            cons,               /**< knapsack constraint */
2165 	   int                   pos                 /**< position of coefficient to delete */
2166 	   )
2167 	{
2168 	   SCIP_CONSHDLR* conshdlr;
2169 	   SCIP_CONSHDLRDATA* conshdlrdata;
2170 	
2171 	   assert(scip != NULL);
2172 	   assert(consdata != NULL);
2173 	   assert(cons != NULL);
2174 	   assert(SCIPconsIsTransformed(cons));
2175 	   assert(!SCIPinProbing(scip));
2176 	
2177 	   SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2178 	      SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2179 	
2180 	   /* remove the rounding locks for the deleted variable */
2181 	   SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2182 	
2183 	   consdata->downlocks[pos] = FALSE;
2184 	   consdata->uplocks[pos] = FALSE;
2185 	
2186 	   if( consdata->linkingconss != NULL )
2187 	   {
2188 	      SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2189 	   }
2190 	
2191 	   /* get event handler */
2192 	   conshdlr = SCIPconsGetHdlr(cons);
2193 	   assert(conshdlr != NULL);
2194 	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
2195 	   assert(conshdlrdata != NULL);
2196 	   assert(conshdlrdata->eventhdlr != NULL);
2197 	
2198 	   /* drop events */
2199 	   SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2200 	
2201 	   SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2202 	      SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2203 	
2204 	   /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2205 	    * position
2206 	    */
2207 	   if( pos != consdata->nvars - 1 )
2208 	   {
2209 	      consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2210 	      consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2211 	      consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2212 	      consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2213 	      consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2214 	
2215 	      if( consdata->linkingconss != NULL )
2216 	      {
2217 	         consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2218 	      }
2219 	   }
2220 	
2221 	   consdata->nvars--;
2222 	   consdata->validsignature = FALSE;
2223 	   consdata->normalized = FALSE;
2224 	
2225 	   return SCIP_OKAY;
2226 	}
2227 	
2228 	/** collect linking constraints for each integer variable */
2229 	static
2230 	SCIP_RETCODE consdataCollectLinkingCons(
2231 	   SCIP*                 scip,               /**< SCIP data structure */
2232 	   SCIP_CONSDATA*        consdata            /**< pointer to consdata */
2233 	   )
2234 	{
2235 	   int nvars;
2236 	   int v;
2237 	
2238 	   assert(scip != NULL);
2239 	   assert(consdata != NULL);
2240 	
2241 	   nvars = consdata->nvars;
2242 	   assert(nvars > 0);
2243 	   assert(consdata->linkingconss == NULL);
2244 	
2245 	   SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2246 	
2247 	   for( v = 0; v < nvars; ++v )
2248 	   {
2249 	      SCIP_CONS* cons;
2250 	      SCIP_VAR* var;
2251 	
2252 	      var = consdata->vars[v];
2253 	      assert(var != NULL);
2254 	
2255 	      SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2256 	
2257 	      /* create linking constraint if it does not exist yet */
2258 	      if( !SCIPexistsConsLinking(scip, var) )
2259 	      {
2260 	         char name[SCIP_MAXSTRLEN];
2261 	
2262 	         (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2263 	
2264 	         /* creates and captures an linking constraint */
2265 	         SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2266 	               TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2267 	         SCIP_CALL( SCIPaddCons(scip, cons) );
2268 	         consdata->linkingconss[v] = cons;
2269 	      }
2270 	      else
2271 	      {
2272 	         consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2273 	         SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2274 	      }
2275 	
2276 	      assert(SCIPexistsConsLinking(scip, var));
2277 	      assert(consdata->linkingconss[v] != NULL);
2278 	      assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2279 	      assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2280 	   }
2281 	
2282 	   return SCIP_OKAY;
2283 	}
2284 	
2285 	/**@} */
2286 	
2287 	
2288 	/**@name Check methods
2289 	 *
2290 	 * @{
2291 	 */
2292 	
2293 	/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2294 	 *  given solution is satisfied
2295 	 */
2296 	static
2297 	SCIP_RETCODE checkCumulativeCondition(
2298 	   SCIP*                 scip,               /**< SCIP data structure */
2299 	   SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
2300 	   int                   nvars,              /**< number of variables (jobs) */
2301 	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
2302 	   int*                  durations,          /**< array containing corresponding durations */
2303 	   int*                  demands,            /**< array containing corresponding demands */
2304 	   int                   capacity,           /**< available cumulative capacity */
2305 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
2306 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
2307 	   SCIP_Bool*            violated,           /**< pointer to store if the cumulative condition is violated */
2308 	   SCIP_CONS*            cons,               /**< constraint which is checked */
2309 	   SCIP_Bool             printreason         /**< should the reason for the violation be printed? */
2310 	   )
2311 	{
2312 	   int* startsolvalues;       /* stores when each job is starting */
2313 	   int* endsolvalues;         /* stores when each job ends */
2314 	   int* startindices;         /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2315 	   int* endindices;           /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2316 	
2317 	   int freecapacity;
2318 	   int curtime;            /* point in time which we are just checking */
2319 	   int endindex;           /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2320 	   int j;
2321 	
2322 	   SCIP_Real absviol;
2323 	   SCIP_Real relviol;
2324 	
2325 	   assert(scip != NULL);
2326 	   assert(violated != NULL);
2327 	
2328 	   (*violated) = FALSE;
2329 	
2330 	   if( nvars == 0 )
2331 	      return SCIP_OKAY;
2332 	
2333 	   assert(vars != NULL);
2334 	   assert(demands != NULL);
2335 	   assert(durations != NULL);
2336 	
2337 	   /* compute time points where we have to check whether capacity constraint is infeasible or not */
2338 	   SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2339 	   SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2340 	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2341 	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2342 	
2343 	   /* assign variables, start and endpoints to arrays */
2344 	   for ( j = 0; j < nvars; ++j )
2345 	   {
2346 	      int solvalue;
2347 	
2348 	      /* the constraint of the cumulative constraint handler should be called after the integrality check */
2349 	      assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2350 	
2351 	      solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2352 	
2353 	      /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2354 	       * jobs which start before hmin to hmin
2355 	       */
2356 	      startsolvalues[j] = MAX(solvalue, hmin);
2357 	      startindices[j] = j;
2358 	
2359 	      endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2360 	      endindices[j] = j;
2361 	   }
2362 	
2363 	   /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2364 	    * corresponding indices in the same way)
2365 	    */
2366 	   SCIPsortIntInt(startsolvalues, startindices, nvars);
2367 	   SCIPsortIntInt(endsolvalues, endindices, nvars);
2368 	
2369 	   endindex = 0;
2370 	   freecapacity = capacity;
2371 	   absviol = 0.0;
2372 	   relviol = 0.0;
2373 	
2374 	   /* check each start point of a job whether the capacity is kept or not */
2375 	   for( j = 0; j < nvars; ++j )
2376 	   {
2377 	      /* only check intervals [hmin,hmax) */
2378 	      curtime = startsolvalues[j];
2379 	
2380 	      if( curtime >= hmax )
2381 	         break;
2382 	
2383 	      /* subtract all capacity needed up to this point */
2384 	      freecapacity -= demands[startindices[j]];
2385 	      while( j+1 < nvars && startsolvalues[j+1] == curtime )
2386 	      {
2387 	         j++;
2388 	         freecapacity -= demands[startindices[j]];
2389 	      }
2390 	
2391 	      /* free all capacity usages of jobs that are no longer running */
2392 	      while( endindex < nvars && curtime >= endsolvalues[endindex] )
2393 	      {
2394 	         freecapacity += demands[endindices[endindex]];
2395 	         ++endindex;
2396 	      }
2397 	      assert(freecapacity <= capacity);
2398 	
2399 	      /* update absolute and relative violation */
2400 	      if( absviol < (SCIP_Real) (-freecapacity) )
2401 	      {
2402 	         absviol = -freecapacity;
2403 	         relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2404 	      }
2405 	
2406 	      /* check freecapacity to be smaller than zero */
2407 	      if( freecapacity < 0 && curtime >= hmin )
2408 	      {
2409 	         SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2410 	         (*violated) = TRUE;
2411 	
2412 	         if( printreason )
2413 	         {
2414 	            int i;
2415 	
2416 	            /* first state the violated constraints */
2417 	            SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2418 	
2419 	            /* second state the reason */
2420 	            SCIPinfoMessage(scip, NULL,
2421 	               ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2422 	               curtime, capacity, capacity - freecapacity);
2423 	
2424 	            for( i = 0; i <= j; ++i )
2425 	            {
2426 	               if( startsolvalues[i] + durations[startindices[i]] > curtime )
2427 	               {
2428 	                  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2429 	                     SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2430 	                     demands[startindices[i]]);
2431 	               }
2432 	            }
2433 	         }
2434 	         break;
2435 	      }
2436 	   } /*lint --e{850}*/
2437 	
2438 	   /* update constraint violation in solution */
2439 	   if( sol != NULL )
2440 	      SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2441 	
2442 	   /* free all buffer arrays */
2443 	   SCIPfreeBufferArray(scip, &endindices);
2444 	   SCIPfreeBufferArray(scip, &startindices);
2445 	   SCIPfreeBufferArray(scip, &endsolvalues);
2446 	   SCIPfreeBufferArray(scip, &startsolvalues);
2447 	
2448 	   return SCIP_OKAY;
2449 	}
2450 	
2451 	/** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2452 	 *  least zero or not. If not (*violated) is set to TRUE
2453 	 */
2454 	static
2455 	SCIP_RETCODE checkCons(
2456 	   SCIP*                 scip,               /**< SCIP data structure */
2457 	   SCIP_CONS*            cons,               /**< constraint to be checked */
2458 	   SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
2459 	   SCIP_Bool*            violated,           /**< pointer to store if the constraint is violated */
2460 	   SCIP_Bool             printreason         /**< should the reason for the violation be printed? */
2461 	   )
2462 	{
2463 	   SCIP_CONSDATA* consdata;
2464 	
2465 	   assert(scip != NULL);
2466 	   assert(cons != NULL);
2467 	   assert(violated != NULL);
2468 	
2469 	   SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2470 	
2471 	   consdata = SCIPconsGetData(cons);
2472 	   assert(consdata != NULL);
2473 	
2474 	   /* check the cumulative condition */
2475 	   SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2476 	         consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2477 	         violated, cons, printreason) );
2478 	
2479 	   return SCIP_OKAY;
2480 	}
2481 	
2482 	/**@} */
2483 	
2484 	/**@name Conflict analysis
2485 	 *
2486 	 * @{
2487 	 */
2488 	
2489 	/** resolves the propagation of the core time algorithm */
2490 	static
2491 	SCIP_RETCODE resolvePropagationCoretimes(
2492 	   SCIP*                 scip,               /**< SCIP data structure */
2493 	   int                   nvars,              /**< number of start time variables (activities) */
2494 	   SCIP_VAR**            vars,               /**< array of start time variables */
2495 	   int*                  durations,          /**< array of durations */
2496 	   int*                  demands,            /**< array of demands */
2497 	   int                   capacity,           /**< cumulative capacity */
2498 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
2499 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
2500 	   SCIP_VAR*             infervar,           /**< inference variable */
2501 	   int                   inferdemand,        /**< demand of the inference variable */
2502 	   int                   inferpeak,          /**< time point which causes the propagation */
2503 	   int                   relaxedpeak,        /**< relaxed time point which would be sufficient to be proved */
2504 	   SCIP_BDCHGIDX*        bdchgidx,           /**< the index of the bound change, representing the point of time where the change took place */
2505 	   SCIP_Bool             usebdwidening,      /**< should bound widening be used during conflict analysis? */
2506 	   int*                  provedpeak,         /**< pointer to store the actually proved peak, or NULL */
2507 	   SCIP_Bool*            explanation         /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2508 	   )
2509 	{
2510 	   SCIP_VAR* var;
2511 	   SCIP_Bool* reported;
2512 	   int duration;
2513 	   int maxlst;
2514 	   int minect;
2515 	   int ect;
2516 	   int lst;
2517 	   int j;
2518 	
2519 	   assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2520 	
2521 	   SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2522 	      SCIPvarGetName(infervar), inferdemand, inferpeak);
2523 	   assert(nvars > 0);
2524 	
2525 	   /* adjusted capacity */
2526 	   capacity -= inferdemand;
2527 	   maxlst = INT_MIN;
2528 	   minect = INT_MAX;
2529 	
2530 	   SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2531 	   BMSclearMemoryArray(reported, nvars);
2532 	
2533 	   /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2534 	    * inference peak and those where the current conflict bounds provide a core at the inference peak
2535 	    */
2536 	   for( j = 0; j < nvars && capacity >= 0; ++j )
2537 	   {
2538 	      var = vars[j];
2539 	      assert(var != NULL);
2540 	
2541 	      /* skip inference variable */
2542 	      if( var == infervar )
2543 	         continue;
2544 	
2545 	      duration = durations[j];
2546 	      assert(duration > 0);
2547 	
2548 	      /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2549 	      assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2550 	      assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2551 	      assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2552 	      assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2553 	
2554 	      SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2555 	         SCIPvarGetName(var),  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var),
2556 	         SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2557 	
2558 	      ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2559 	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2560 	
2561 	      /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2562 	       * that job without adding it the explanation
2563 	       */
2564 	      if( inferpeak < ect && lst <= inferpeak )
2565 	      {
2566 	         capacity -= demands[j];
2567 	         reported[j] = TRUE;
2568 	
2569 	         maxlst = MAX(maxlst, lst);
2570 	         minect = MIN(minect, ect);
2571 	         assert(maxlst < minect);
2572 	
2573 	         if( explanation != NULL )
2574 	            explanation[j] = TRUE;
2575 	
2576 	         continue;
2577 	      }
2578 	
2579 	      /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2580 	       * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2581 	       * not part of the conflict yet we get the global bounds back.
2582 	       */
2583 	      ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2584 	      lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2585 	
2586 	      /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2587 	       * of that job without and collect the job as part of the explanation
2588 	       *
2589 	       * @note we do not need to reported that job to SCIP since the required bounds are already reported
2590 	       */
2591 	      if( inferpeak < ect && lst <= inferpeak )
2592 	      {
2593 	         capacity -= demands[j];
2594 	         reported[j] = TRUE;
2595 	
2596 	         maxlst = MAX(maxlst, lst);
2597 	         minect = MIN(minect, ect);
2598 	         assert(maxlst < minect);
2599 	
2600 	         if( explanation != NULL )
2601 	            explanation[j] = TRUE;
2602 	      }
2603 	   }
2604 	
2605 	   if( capacity >= 0 )
2606 	   {
2607 	      int* cands;
2608 	      int* canddemands;
2609 	      int ncands;
2610 	      int c;
2611 	
2612 	      SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2613 	      SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2614 	      ncands = 0;
2615 	
2616 	      /* collect all cores of the variables which lay in the considered time window except the inference variable */
2617 	      for( j = 0; j < nvars; ++j )
2618 	      {
2619 	         var = vars[j];
2620 	         assert(var != NULL);
2621 	
2622 	         /* skip inference variable */
2623 	         if( var == infervar || reported[j] )
2624 	            continue;
2625 	
2626 	         duration = durations[j];
2627 	         assert(duration > 0);
2628 	
2629 	         /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2630 	         assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2631 	         assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2632 	         assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2633 	         assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2634 	
2635 	         /* collect local core information */
2636 	         ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2637 	         lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2638 	
2639 	         SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2640 	            SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2641 	            SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2642 	
2643 	         /* check if the inference peak is part of the core */
2644 	         if( inferpeak < ect && lst <= inferpeak )
2645 	         {
2646 	            cands[ncands] = j;
2647 	            canddemands[ncands] = demands[j];
2648 	            ncands++;
2649 	
2650 	            capacity -= demands[j];
2651 	         }
2652 	      }
2653 	
2654 	      /* sort candidates indices w.r.t. their demands */
2655 	      SCIPsortDownIntInt(canddemands, cands, ncands);
2656 	
2657 	      assert(capacity < 0);
2658 	      assert(ncands > 0);
2659 	
2660 	      /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2661 	      while( capacity + canddemands[ncands-1] < 0 )
2662 	      {
2663 	         ncands--;
2664 	         capacity += canddemands[ncands];
2665 	         assert(ncands > 0);
2666 	      }
2667 	
2668 	      /* compute the size (number of time steps) of the job cores */
2669 	      for( c = 0; c < ncands; ++c )
2670 	      {
2671 	         var = vars[cands[c]];
2672 	         assert(var != NULL);
2673 	
2674 	         duration = durations[cands[c]];
2675 	
2676 	         ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2677 	         lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2678 	
2679 	         maxlst = MAX(maxlst, lst);
2680 	         minect = MIN(minect, ect);
2681 	         assert(maxlst < minect);
2682 	      }
2683 	
2684 	      SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2685 	      assert(inferpeak >= maxlst);
2686 	      assert(inferpeak < minect);
2687 	
2688 	      /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2689 	      if( relaxedpeak < inferpeak )
2690 	      {
2691 	         inferpeak = MAX(maxlst, relaxedpeak);
2692 	      }
2693 	      else if( relaxedpeak > inferpeak )
2694 	      {
2695 	         inferpeak = MIN(minect-1, relaxedpeak);
2696 	      }
2697 	      assert(inferpeak >= hmin);
2698 	      assert(inferpeak < hmax);
2699 	      assert(inferpeak >= maxlst);
2700 	      assert(inferpeak < minect);
2701 	
2702 	      /* post all necessary bound changes */
2703 	      for( c = 0; c < ncands; ++c )
2704 	      {
2705 	         var = vars[cands[c]];
2706 	         assert(var != NULL);
2707 	
2708 	         if( usebdwidening )
2709 	         {
2710 	            duration = durations[cands[c]];
2711 	
2712 	            SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2713 	            SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2714 	         }
2715 	         else
2716 	         {
2717 	            SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2718 	            SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2719 	         }
2720 	
2721 	         if( explanation != NULL )
2722 	            explanation[cands[c]] = TRUE;
2723 	      }
2724 	
2725 	      SCIPfreeBufferArray(scip, &canddemands);
2726 	      SCIPfreeBufferArray(scip, &cands);
2727 	   }
2728 	
2729 	   SCIPfreeBufferArray(scip, &reported);
2730 	
2731 	   if( provedpeak != NULL )
2732 	      *provedpeak = inferpeak;
2733 	
2734 	   return SCIP_OKAY;
2735 	}
2736 	
2737 	#if 0
2738 	/** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2739 	 *  energy in total and for bound change is enough
2740 	 */
2741 	static
2742 	SCIP_RETCODE resolvePropagationEdgeFinding(
2743 	   SCIP*                 scip,               /**< SCIP data structure */
2744 	   int                   nvars,              /**< number of start time variables (activities) */
2745 	   SCIP_VAR**            vars,               /**< array of start time variables */
2746 	   int*                  durations,          /**< array of durations */
2747 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
2748 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
2749 	   SCIP_VAR*             infervar,           /**< variable whose bound change is to be explained */
2750 	   INFERINFO             inferinfo,          /**< inference info containing position of correct bdchgids */
2751 	   SCIP_BOUNDTYPE        boundtype,          /**< the type of the changed bound (lower or upper bound) */
2752 	   SCIP_BDCHGIDX*        bdchgidx,           /**< the index of the bound change, representing the point of time where the change took place */
2753 	   SCIP_Bool             usebdwidening,      /**< should bound widening be used during conflict analysis? */
2754 	   SCIP_Bool*            explanation         /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2755 	   )
2756 	{
2757 	   int est;
2758 	   int lct;
2759 	   int j;
2760 	
2761 	   /* ???????????????????? do bound widening */
2762 	
2763 	   assert(scip != NULL);
2764 	   assert(nvars > 0);
2765 	   assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2766 	
2767 	   SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2768 	
2769 	   if( boundtype == SCIP_BOUNDTYPE_LOWER )
2770 	   {
2771 	      SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2772 	   }
2773 	   else
2774 	   {
2775 	      SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2776 	   }
2777 	
2778 	   est = inferInfoGetData1(inferinfo);
2779 	   lct = inferInfoGetData2(inferinfo);
2780 	   assert(est < lct);
2781 	
2782 	   /* collect the energies of all variables in [est_omega, lct_omega] */
2783 	   for( j = 0; j < nvars; ++j )
2784 	   {
2785 	      SCIP_VAR* var;
2786 	      SCIP_Bool left;
2787 	      SCIP_Bool right;
2788 	      int duration;
2789 	      int lb;
2790 	      int ub;
2791 	
2792 	      var = vars[j];
2793 	      assert(var != NULL);
2794 	
2795 	      if( var == infervar )
2796 	      {
2797 	         if( explanation != NULL )
2798 	            explanation[j] = TRUE;
2799 	
2800 	         continue;
2801 	      }
2802 	
2803 	      lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2804 	      ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2805 	
2806 	      duration = durations[j];
2807 	      assert(duration > 0);
2808 	
2809 	      /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2810 	       * since we use adjusted jobs during the propagation
2811 	       */
2812 	      left = (est == hmin && lb + duration > hmin) || lb >= est;
2813 	
2814 	      /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2815 	       * since we use adjusted jobs during the propagation
2816 	       */
2817 	      right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2818 	
2819 	      /* store all jobs running in [est_omega; lct_omega] */
2820 	      if( left && right  )
2821 	      {
2822 	         /* check if bound widening should be used */
2823 	         if( usebdwidening )
2824 	         {
2825 	            SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2826 	            SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2827 	         }
2828 	         else
2829 	         {
2830 	            SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2831 	            SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2832 	         }
2833 	
2834 	         if( explanation != NULL )
2835 	            explanation[j] = TRUE;
2836 	      }
2837 	   }
2838 	
2839 	   return SCIP_OKAY;
2840 	}
2841 	#endif
2842 	
2843 	/** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2844 	static
2845 	int computeOverlap(
2846 	   int                   begin,              /**< begin of the times interval */
2847 	   int                   end,                /**< end of time interval */
2848 	   int                   est,                /**< earliest start time */
2849 	   int                   lst,                /**< latest start time */
2850 	   int                   duration            /**< duration of the job */
2851 	   )
2852 	{
2853 	   int left;
2854 	   int right;
2855 	   int ect;
2856 	   int lct;
2857 	
2858 	   ect = est + duration;
2859 	   lct = lst + duration;
2860 	
2861 	   /* check if job runs completely within [begin,end) */
2862 	   if( lct <= end && est >= begin )
2863 	      return duration;
2864 	
2865 	   assert(lst <= end && ect >= begin);
2866 	
2867 	   left = ect - begin;
2868 	   assert(left > 0);
2869 	
2870 	   right = end - lst;
2871 	   assert(right > 0);
2872 	
2873 	   return MIN3(left, right, end - begin);
2874 	}
2875 	
2876 	/** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2877 	 *  reason
2878 	 *
2879 	 *  @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2880 	 */
2881 	static
2882 	SCIP_RETCODE analyzeEnergyRequirement(
2883 	   SCIP*                 scip,               /**< SCIP data structure */
2884 	   int                   nvars,              /**< number of start time variables (activities) */
2885 	   SCIP_VAR**            vars,               /**< array of start time variables */
2886 	   int*                  durations,          /**< array of durations */
2887 	   int*                  demands,            /**< array of demands */
2888 	   int                   capacity,           /**< capacity of the cumulative condition */
2889 	   int                   begin,              /**< begin of the time window */
2890 	   int                   end,                /**< end of the time window */
2891 	   SCIP_VAR*             infervar,           /**< variable which was propagate, or NULL */
2892 	   SCIP_BOUNDTYPE        boundtype,          /**< the type of the changed bound (lower or upper bound) */
2893 	   SCIP_BDCHGIDX*        bdchgidx,           /**< the index of the bound change, representing the point of time where the change took place */
2894 	   SCIP_Real             relaxedbd,          /**< the relaxed bound which is sufficient to be explained */
2895 	   SCIP_Bool             usebdwidening,      /**< should bound widening be used during conflict analysis? */
2896 	   SCIP_Bool*            explanation         /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2897 	   )
2898 	{
2899 	   int* locenergies;
2900 	   int* overlaps;
2901 	   int* idxs;
2902 	
2903 	   SCIP_Longint requiredenergy;
2904 	   int v;
2905 	
2906 	   SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2907 	   SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2908 	   SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2909 	
2910 	   /* energy which needs be explained */
2911 	   requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2912 	
2913 	   SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2914 	
2915 	   /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2916 	    * takes
2917 	    */
2918 	   for( v = 0; v < nvars; ++v )
2919 	   {
2920 	      SCIP_VAR* var;
2921 	      int glbenergy;
2922 	      int duration;
2923 	      int demand;
2924 	      int est;
2925 	      int lst;
2926 	
2927 	      var = vars[v];
2928 	      assert(var != NULL);
2929 	
2930 	      locenergies[v] = 0;
2931 	      overlaps[v] = 0;
2932 	      idxs[v] = v;
2933 	
2934 	      demand = demands[v];
2935 	      assert(demand > 0);
2936 	
2937 	      duration = durations[v];
2938 	      assert(duration > 0);
2939 	
2940 	      /* check if the variable equals the inference variable (the one which was propagated) */
2941 	      if( infervar == var )
2942 	      {
2943 	         int overlap;
2944 	         int right;
2945 	         int left;
2946 	
2947 	         assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2948 	
2949 	         SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2950 	            SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2951 	            boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2952 	
2953 	         /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2954 	          * which is necessary from the inference variable
2955 	          */
2956 	         if( boundtype == SCIP_BOUNDTYPE_UPPER )
2957 	         {
2958 	            int lct;
2959 	
2960 	            /* get the latest start time of the infer start time variable before the propagation took place */
2961 	            lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2962 	
2963 	            /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2964 	             * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2965 	             * scheduled w.r.t. its latest start time
2966 	             */
2967 	            assert(lst < end);
2968 	
2969 	            /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2970 	             * interval (before the propagation)
2971 	             */
2972 	            right = MIN3(end - lst, end - begin, duration);
2973 	
2974 	            /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2975 	            assert(right > 0);
2976 	
2977 	            lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2978 	            assert(begin <= lct);
2979 	            assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2980 	
2981 	            /* compute the overlap of the job after the propagation but considering the relaxed bound */
2982 	            left = MIN(lct - begin + 1, end - begin);
2983 	            assert(left > 0);
2984 	
2985 	            /* compute the minimum overlap; */
2986 	            overlap = MIN(left, right);
2987 	            assert(overlap > 0);
2988 	            assert(overlap <= end - begin);
2989 	            assert(overlap <= duration);
2990 	
2991 	            if( usebdwidening )
2992 	            {
2993 	               assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2994 	               SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2995 	            }
2996 	            else
2997 	            {
2998 	               SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2999 	            }
3000 	         }
3001 	         else
3002 	         {
3003 	            int ect;
3004 	
3005 	            assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3006 	
3007 	            /* get the earliest completion time of the infer start time variable before the propagation took place */
3008 	            ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
3009 	
3010 	            /* the earliest start time of the inference start time variable before the propagation needs to be larger as
3011 	             * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
3012 	             * the job is scheduled w.r.t. its earliest start time
3013 	             */
3014 	            assert(ect > begin);
3015 	
3016 	            /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
3017 	             * interval (before the propagation)
3018 	             */
3019 	            left = MIN3(ect - begin, end - begin, duration);
3020 	
3021 	            /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
3022 	            assert(left > 0);
3023 	
3024 	            est = SCIPconvertRealToInt(scip, relaxedbd);
3025 	            assert(end >= est);
3026 	            assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
3027 	
3028 	            /* compute the overlap of the job after the propagation but considering the relaxed bound */
3029 	            right = MIN(end - est + 1, end - begin);
3030 	            assert(right > 0);
3031 	
3032 	            /* compute the minimum overlap */
3033 	            overlap = MIN(left, right);
3034 	            assert(overlap > 0);
3035 	            assert(overlap <= end - begin);
3036 	            assert(overlap <= duration);
3037 	
3038 	            if( usebdwidening )
3039 	            {
3040 	               assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3041 	               SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3042 	            }
3043 	            else
3044 	            {
3045 	               SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3046 	            }
3047 	         }
3048 	
3049 	         /* subtract the amount of energy which is available due to the overlap of the inference start time */
3050 	         requiredenergy -= (SCIP_Longint) overlap * demand;
3051 	
3052 	         if( explanation != NULL )
3053 	            explanation[v] = TRUE;
3054 	
3055 	         continue;
3056 	      }
3057 	
3058 	      /* global time points */
3059 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3060 	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3061 	
3062 	      glbenergy = 0;
3063 	
3064 	      /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3065 	       * time window
3066 	       */
3067 	      if( est + duration > begin && lst < end )
3068 	      {
3069 	         /* evaluated global contribution */
3070 	         glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3071 	
3072 	         /* remove the globally available energy form the required energy */
3073 	         requiredenergy -= glbenergy;
3074 	
3075 	         if( explanation != NULL )
3076 	            explanation[v] = TRUE;
3077 	      }
3078 	
3079 	      /* local time points */
3080 	      est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3081 	      lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3082 	
3083 	      /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3084 	       * time window
3085 	       */
3086 	      if( est + duration > begin && lst < end )
3087 	      {
3088 	         overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3089 	
3090 	         /* evaluated additionally local energy contribution */
3091 	         locenergies[v] = overlaps[v] * demand - glbenergy;
3092 	         assert(locenergies[v] >= 0);
3093 	      }
3094 	   }
3095 	
3096 	   /* sort the variable contributions w.r.t. additional local energy contributions */
3097 	   SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3098 	
3099 	   /* add local energy contributions until an overload is implied */
3100 	   for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3101 	   {
3102 	      SCIP_VAR* var;
3103 	      int duration;
3104 	      int overlap;
3105 	      int relaxlb;
3106 	      int relaxub;
3107 	      int idx;
3108 	
3109 	      idx = idxs[v];
3110 	      assert(idx >= 0 && idx < nvars);
3111 	
3112 	      var = vars[idx];
3113 	      assert(var != NULL);
3114 	      assert(var != infervar);
3115 	
3116 	      duration = durations[idx];
3117 	      assert(duration > 0);
3118 	
3119 	      overlap = overlaps[v];
3120 	      assert(overlap > 0);
3121 	
3122 	      requiredenergy -= locenergies[v];
3123 	
3124 	      if( requiredenergy < -1 )
3125 	      {
3126 	         int demand;
3127 	
3128 	         demand = demands[idx];
3129 	         assert(demand > 0);
3130 	
3131 	         overlap += (int)((requiredenergy + 1) / demand);
3132 	
3133 	#ifndef NDEBUG
3134 	         requiredenergy += locenergies[v];
3135 	         requiredenergy -= (SCIP_Longint) overlap * demand;
3136 	         assert(requiredenergy < 0);
3137 	#endif
3138 	      }
3139 	      assert(overlap > 0);
3140 	
3141 	      relaxlb = begin - duration + overlap;
3142 	      relaxub = end - overlap;
3143 	
3144 	      SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3145 	         SCIPvarGetName(var),
3146 	         SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var),
3147 	         SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
3148 	         SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3149 	         relaxlb, relaxub, demands[idx], duration);
3150 	
3151 	      SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3152 	      SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3153 	
3154 	      if( explanation != NULL )
3155 	         explanation[idx] = TRUE;
3156 	   }
3157 	
3158 	   assert(requiredenergy < 0);
3159 	
3160 	   SCIPfreeBufferArray(scip, &idxs);
3161 	   SCIPfreeBufferArray(scip, &overlaps);
3162 	   SCIPfreeBufferArray(scip, &locenergies);
3163 	
3164 	   return SCIP_OKAY;
3165 	}
3166 	
3167 	/** resolve propagation w.r.t. the cumulative condition */
3168 	static
3169 	SCIP_RETCODE respropCumulativeCondition(
3170 	   SCIP*                 scip,               /**< SCIP data structure */
3171 	   int                   nvars,              /**< number of start time variables (activities) */
3172 	   SCIP_VAR**            vars,               /**< array of start time variables */
3173 	   int*                  durations,          /**< array of durations */
3174 	   int*                  demands,            /**< array of demands */
3175 	   int                   capacity,           /**< cumulative capacity */
3176 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
3177 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
3178 	   SCIP_VAR*             infervar,           /**< the conflict variable whose bound change has to be resolved */
3179 	   INFERINFO             inferinfo,          /**< the user information */
3180 	   SCIP_BOUNDTYPE        boundtype,          /**< the type of the changed bound (lower or upper bound) */
3181 	   SCIP_BDCHGIDX*        bdchgidx,           /**< the index of the bound change, representing the point of time where the change took place */
3182 	   SCIP_Real             relaxedbd,          /**< the relaxed bound which is sufficient to be explained */
3183 	   SCIP_Bool             usebdwidening,      /**< should bound widening be used during conflict analysis? */
3184 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3185 	   SCIP_RESULT*          result              /**< pointer to store the result of the propagation conflict resolving call */
3186 	   )
3187 	{
3188 	   switch( inferInfoGetProprule(inferinfo) )
3189 	   {
3190 	   case PROPRULE_1_CORETIMES:
3191 	   {
3192 	      int inferdemand;
3193 	      int inferduration;
3194 	      int inferpos;
3195 	      int inferpeak;
3196 	      int relaxedpeak;
3197 	      int provedpeak;
3198 	
3199 	      /* get the position of the inferred variable in the vars array */
3200 	      inferpos = inferInfoGetData1(inferinfo);
3201 	      if( inferpos >= nvars || vars[inferpos] != infervar )
3202 	      {
3203 	         /* find inference variable in constraint */
3204 	         for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3205 	         {}
3206 	      }
3207 	      assert(inferpos < nvars);
3208 	      assert(vars[inferpos] == infervar);
3209 	
3210 	      inferdemand = demands[inferpos];
3211 	      inferduration = durations[inferpos];
3212 	
3213 	      if( boundtype == SCIP_BOUNDTYPE_UPPER )
3214 	      {
3215 	         /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3216 	          * the inference variable
3217 	          */
3218 	         assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3219 	
3220 	         SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3221 	            SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3222 	            SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3223 	
3224 	         /* get the inference peak that the time point which lead to the that propagtion */
3225 	         inferpeak = inferInfoGetData2(inferinfo);
3226 	         /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3227 	          * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3228 	          */
3229 	         assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3230 	         relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3231 	
3232 	         /* make sure that the relaxed peak is part of the effective horizon */
3233 	         relaxedpeak = MIN(relaxedpeak, hmax-1);
3234 	
3235 	         /* make sure that relaxed peak is not larger than the infer peak
3236 	          *
3237 	          * This can happen in case the variable is not an active variable!
3238 	          */
3239 	         relaxedpeak = MAX(relaxedpeak, inferpeak);
3240 	         assert(relaxedpeak >= inferpeak);
3241 	         assert(relaxedpeak >= hmin);
3242 	      }
3243 	      else
3244 	      {
3245 	         assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3246 	
3247 	         SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3248 	            SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3249 	            SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3250 	
3251 	         /* get the time interval where the job could not be scheduled */
3252 	         inferpeak = inferInfoGetData2(inferinfo);
3253 	         /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3254 	          * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3255 	          */
3256 	         assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3257 	         relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3258 	
3259 	         /* make sure that the relaxed peak is part of the effective horizon */
3260 	         relaxedpeak = MAX(relaxedpeak, hmin);
3261 	
3262 	         /* make sure that relaxed peak is not larger than the infer peak
3263 	          *
3264 	          * This can happen in case the variable is not an active variable!
3265 	          */
3266 	         relaxedpeak = MIN(relaxedpeak, inferpeak);
3267 	         assert(relaxedpeak < hmax);
3268 	      }
3269 	
3270 	      /* resolves the propagation of the core time algorithm */
3271 	      SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3272 	            infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3273 	
3274 	      if( boundtype == SCIP_BOUNDTYPE_UPPER )
3275 	      {
3276 	         if( usebdwidening )
3277 	         {
3278 	            SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL,  (SCIP_Real)provedpeak) );
3279 	         }
3280 	         else
3281 	         {
3282 	            /* old upper bound of variable itself is part of the explanation */
3283 	            SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3284 	         }
3285 	      }
3286 	      else
3287 	      {
3288 	         assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3289 	
3290 	         if( usebdwidening )
3291 	         {
3292 	            SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3293 	         }
3294 	         else
3295 	         {
3296 	            /* old lower bound of variable itself is part of the explanation */
3297 	            SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3298 	         }
3299 	      }
3300 	
3301 	      if( explanation != NULL )
3302 	         explanation[inferpos] = TRUE;
3303 	
3304 	      break;
3305 	   }
3306 	   case PROPRULE_2_EDGEFINDING:
3307 	   case PROPRULE_3_TTEF:
3308 	   {
3309 	      int begin;
3310 	      int end;
3311 	
3312 	      begin = inferInfoGetData1(inferinfo);
3313 	      end = inferInfoGetData2(inferinfo);
3314 	      assert(begin < end);
3315 	
3316 	      begin = MAX(begin, hmin);
3317 	      end = MIN(end, hmax);
3318 	
3319 	      SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3320 	            begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3321 	
3322 	      break;
3323 	   }
3324 	
3325 	   case PROPRULE_0_INVALID:
3326 	   default:
3327 	      SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3328 	      SCIPABORT();
3329 	      return SCIP_INVALIDDATA; /*lint !e527*/
3330 	   }
3331 	
3332 	   (*result) = SCIP_SUCCESS;
3333 	
3334 	   return SCIP_OKAY;
3335 	}
3336 	
3337 	/**@} */
3338 	
3339 	
3340 	/**@name Enforcement methods
3341 	 *
3342 	 * @{
3343 	 */
3344 	
3345 	/** apply all fixings which are given by the alternative bounds */
3346 	static
3347 	SCIP_RETCODE applyAlternativeBoundsBranching(
3348 	   SCIP*                 scip,               /**< SCIP data structure */
3349 	   SCIP_VAR**            vars,               /**< array of active variables */
3350 	   int                   nvars,              /**< number of active variables */
3351 	   int*                  alternativelbs,     /**< alternative lower bounds */
3352 	   int*                  alternativeubs,     /**< alternative lower bounds */
3353 	   int*                  downlocks,          /**< number of constraints with down lock participating by the computation */
3354 	   int*                  uplocks,            /**< number of constraints with up lock participating by the computation */
3355 	   SCIP_Bool*            branched            /**< pointer to store if a branching was applied */
3356 	   )
3357 	{
3358 	   int v;
3359 	
3360 	   for( v = 0; v < nvars; ++v )
3361 	   {
3362 	      SCIP_VAR* var;
3363 	      SCIP_Real objval;
3364 	
3365 	      var = vars[v];
3366 	      assert(var != NULL);
3367 	
3368 	      objval = SCIPvarGetObj(var);
3369 	
3370 	      if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3371 	      {
3372 	         int ub;
3373 	
3374 	         ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3375 	
3376 	         if( alternativelbs[v] <= ub )
3377 	         {
3378 	            SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3379 	            (*branched) = TRUE;
3380 	
3381 	            SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3382 	               SCIPvarGetLbLocal(var), alternativelbs[v]);
3383 	
3384 	            return SCIP_OKAY;
3385 	         }
3386 	      }
3387 	
3388 	      if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3389 	      {
3390 	         int lb;
3391 	
3392 	         lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3393 	
3394 	         if( alternativeubs[v] >= lb )
3395 	         {
3396 	            SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3397 	            (*branched) = TRUE;
3398 	
3399 	            SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3400 	               alternativeubs[v],  SCIPvarGetUbLocal(var));
3401 	
3402 	            return SCIP_OKAY;
3403 	         }
3404 	      }
3405 	   }
3406 	
3407 	   return SCIP_OKAY;
3408 	}
3409 	
3410 	/** remove the capacity requirments for all job which start at the curtime */
3411 	static
3412 	void subtractStartingJobDemands(
3413 	   SCIP_CONSDATA*        consdata,           /**< constraint data */
3414 	   int                   curtime,            /**< current point in time */
3415 	   int*                  starttimes,         /**< array of start times */
3416 	   int*                  startindices,       /**< permutation with respect to the start times */
3417 	   int*                  freecapacity,       /**< pointer to store the resulting free capacity */
3418 	   int*                  idx,                /**< pointer to index in start time array */
3419 	   int                   nvars               /**< number of vars in array of starttimes and startindices */
3420 	   )
3421 	{
3422 	#if defined SCIP_DEBUG && !defined NDEBUG
3423 	   int oldidx;
3424 	
3425 	   assert(idx != NULL);
3426 	   oldidx = *idx;
3427 	#else
3428 	   assert(idx != NULL);
3429 	#endif
3430 	
3431 	   assert(starttimes != NULL);
3432 	   assert(starttimes != NULL);
3433 	   assert(freecapacity != NULL);
3434 	   assert(starttimes[*idx] == curtime);
3435 	   assert(consdata->demands != NULL);
3436 	   assert(freecapacity != idx);
3437 	
3438 	   /* subtract all capacity needed up to this point */
3439 	   (*freecapacity) -= consdata->demands[startindices[*idx]];
3440 	
3441 	   while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3442 	   {
3443 	      ++(*idx);
3444 	      (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3445 	      assert(freecapacity != idx);
3446 	   }
3447 	#ifdef SCIP_DEBUG
3448 	   assert(oldidx <= *idx);
3449 	#endif
3450 	}
3451 	
3452 	/** add the capacity requirments for all job which end at the curtime */
3453 	static
3454 	void addEndingJobDemands(
3455 	   SCIP_CONSDATA*        consdata,           /**< constraint data */
3456 	   int                   curtime,            /**< current point in time */
3457 	   int*                  endtimes,           /**< array of end times */
3458 	   int*                  endindices,         /**< permutation with rspect to the end times */
3459 	   int*                  freecapacity,       /**< pointer to store the resulting free capacity */
3460 	   int*                  idx,                /**< pointer to index in end time array */
3461 	   int                   nvars               /**< number of vars in array of starttimes and startindices */
3462 	   )
3463 	{
3464 	#if defined SCIP_DEBUG && !defined NDEBUG
3465 	   int oldidx;
3466 	   oldidx = *idx;
3467 	#endif
3468 	
3469 	   /* free all capacity usages of jobs the are no longer running */
3470 	   while( endtimes[*idx] <= curtime && *idx < nvars)
3471 	   {
3472 	      (*freecapacity) += consdata->demands[endindices[*idx]];
3473 	      ++(*idx);
3474 	   }
3475 	
3476 	#ifdef SCIP_DEBUG
3477 	   assert(oldidx <= *idx);
3478 	#endif
3479 	}
3480 	
3481 	/** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3482 	static
3483 	SCIP_RETCODE computePeak(
3484 	   SCIP*                 scip,               /**< SCIP data structure */
3485 	   SCIP_CONSDATA*        consdata,           /**< constraint handler data */
3486 	   SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
3487 	   int*                  timepoint           /**< pointer to store the time point of the peak */
3488 	   )
3489 	{
3490 	   int* starttimes;         /* stores when each job is starting */
3491 	   int* endtimes;           /* stores when each job ends */
3492 	   int* startindices;       /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3493 	   int* endindices;         /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3494 	
3495 	   int nvars;               /* number of activities for this constraint */
3496 	   int freecapacity;        /* remaining capacity */
3497 	   int curtime;             /* point in time which we are just checking */
3498 	   int endindex;            /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3499 	
3500 	   int hmin;
3501 	   int hmax;
3502 	
3503 	   int j;
3504 	
3505 	   assert(consdata != NULL);
3506 	
3507 	   nvars = consdata->nvars;
3508 	   assert(nvars > 0);
3509 	
3510 	   *timepoint = consdata->hmax;
3511 	
3512 	   assert(consdata->vars != NULL);
3513 	
3514 	   SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3515 	   SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3516 	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3517 	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3518 	
3519 	   /* create event point arrays */
3520 	   createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3521 	      starttimes, endtimes, startindices, endindices);
3522 	
3523 	   endindex = 0;
3524 	   freecapacity = consdata->capacity;
3525 	   hmin = consdata->hmin;
3526 	   hmax = consdata->hmax;
3527 	
3528 	   /* check each startpoint of a job whether the capacity is kept or not */
3529 	   for( j = 0; j < nvars; ++j )
3530 	   {
3531 	      curtime = starttimes[j];
3532 	      SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3533 	
3534 	      if( curtime >= hmax )
3535 	         break;
3536 	
3537 	      /* remove the capacity requirments for all job which start at the curtime */
3538 	      subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3539 	
3540 	      /* add the capacity requirments for all job which end at the curtime */
3541 	      addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3542 	
3543 	      assert(freecapacity <= consdata->capacity);
3544 	      assert(endindex <= nvars);
3545 	
3546 	      /* endindex - points to the next job which will finish */
3547 	      /* j - points to the last job that has been released */
3548 	
3549 	      /* if free capacity is smaller than zero, then add branching candidates */
3550 	      if( freecapacity < 0 && curtime >= hmin )
3551 	      {
3552 	         *timepoint = curtime;
3553 	         break;
3554 	      }
3555 	   } /*lint --e{850}*/
3556 	
3557 	   /* free all buffer arrays */
3558 	   SCIPfreeBufferArray(scip, &endindices);
3559 	   SCIPfreeBufferArray(scip, &startindices);
3560 	   SCIPfreeBufferArray(scip, &endtimes);
3561 	   SCIPfreeBufferArray(scip, &starttimes);
3562 	
3563 	   return SCIP_OKAY;
3564 	}
3565 	
3566 	/** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3567 	static
3568 	SCIP_RETCODE collectBranchingCands(
3569 	   SCIP*                 scip,               /**< SCIP data structure */
3570 	   SCIP_CONS**           conss,              /**< constraints to be processed */
3571 	   int                   nconss,             /**< number of constraints */
3572 	   SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
3573 	   int*                  nbranchcands        /**< pointer to store the number of branching variables */
3574 	   )
3575 	{
3576 	   SCIP_HASHTABLE* collectedvars;
3577 	   int c;
3578 	
3579 	   assert(scip != NULL);
3580 	   assert(conss != NULL);
3581 	
3582 	   /* create a hash table */
3583 	   SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3584 	         SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3585 	
3586 	   assert(scip != NULL);
3587 	   assert(conss != NULL);
3588 	
3589 	   for( c = 0; c < nconss; ++c )
3590 	   {
3591 	      SCIP_CONS* cons;
3592 	      SCIP_CONSDATA* consdata;
3593 	
3594 	      int curtime;
3595 	      int j;
3596 	
3597 	      cons = conss[c];
3598 	      assert(cons != NULL);
3599 	
3600 	      if( !SCIPconsIsActive(cons) )
3601 	         continue;
3602 	
3603 	      consdata = SCIPconsGetData(cons);
3604 	      assert(consdata != NULL);
3605 	
3606 	      /* get point in time when capacity is exceeded */
3607 	      SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3608 	
3609 	      if( curtime < consdata->hmin || curtime >= consdata->hmax )
3610 	         continue;
3611 	
3612 	      /* report all variables that are running at that point in time */
3613 	      for( j = 0; j < consdata->nvars; ++j )
3614 	      {
3615 	         SCIP_VAR* var;
3616 	         int lb;
3617 	         int ub;
3618 	
3619 	         var = consdata->vars[j];
3620 	         assert(var != NULL);
3621 	
3622 	         /* check if the variable was already added */
3623 	         if( SCIPhashtableExists(collectedvars, (void*)var) )
3624 	            continue;
3625 	
3626 	         lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3627 	         ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3628 	
3629 	         if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub  )
3630 	         {
3631 	            SCIP_Real solval;
3632 	            SCIP_Real score;
3633 	
3634 	            solval = SCIPgetSolVal(scip, sol, var);
3635 	            score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3636 	
3637 	            SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3638 	            SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3639 	            (*nbranchcands)++;
3640 	
3641 	            SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3642 	         }
3643 	      }
3644 	   }
3645 	
3646 	   SCIPhashtableFree(&collectedvars);
3647 	
3648 	   SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3649 	
3650 	   return SCIP_OKAY;
3651 	}
3652 	
3653 	/** enforcement of an LP, pseudo, or relaxation solution */
3654 	static
3655 	SCIP_RETCODE enforceSolution(
3656 	   SCIP*                 scip,               /**< SCIP data structure */
3657 	   SCIP_CONS**           conss,              /**< constraints to be processed */
3658 	   int                   nconss,             /**< number of constraints */
3659 	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for LP or pseudo solution) */
3660 	   SCIP_Bool             branch,             /**< should branching candidates be collected */
3661 	   SCIP_RESULT*          result              /**< pointer to store the result */
3662 	   )
3663 	{
3664 	   if( branch )
3665 	   {
3666 	      int nbranchcands;
3667 	
3668 	      nbranchcands = 0;
3669 	      SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3670 	
3671 	      if( nbranchcands > 0 )
3672 	         (*result) = SCIP_INFEASIBLE;
3673 	   }
3674 	   else
3675 	   {
3676 	      SCIP_Bool violated;
3677 	      int c;
3678 	
3679 	      violated = FALSE;
3680 	
3681 	      /* first check if a constraints is violated */
3682 	      for( c = 0; c < nconss && !violated; ++c )
3683 	      {
3684 	         SCIP_CONS* cons;
3685 	
3686 	         cons = conss[c];
3687 	         assert(cons != NULL);
3688 	
3689 	         SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3690 	      }
3691 	
3692 	      if( violated )
3693 	         (*result) = SCIP_INFEASIBLE;
3694 	   }
3695 	
3696 	   return SCIP_OKAY;
3697 	}
3698 	
3699 	/**@} */
3700 	
3701 	/**@name Propagation
3702 	 *
3703 	 * @{
3704 	 */
3705 	
3706 	/** check if cumulative constraint is independently of all other constraints */
3707 	static
3708 	SCIP_Bool isConsIndependently(
3709 	   SCIP_CONS*            cons                /**< cumulative constraint */
3710 	   )
3711 	{
3712 	   SCIP_CONSDATA* consdata;
3713 	   SCIP_VAR** vars;
3714 	   SCIP_Bool* downlocks;
3715 	   SCIP_Bool* uplocks;
3716 	   int nvars;
3717 	   int v;
3718 	
3719 	   consdata = SCIPconsGetData(cons);
3720 	   assert(consdata != NULL);
3721 	
3722 	   nvars = consdata->nvars;
3723 	   vars = consdata->vars;
3724 	   downlocks = consdata->downlocks;
3725 	   uplocks = consdata->uplocks;
3726 	
3727 	   /* check if the cumulative constraint has the only locks on the involved variables */
3728 	   for( v = 0; v < nvars; ++v )
3729 	   {
3730 	      SCIP_VAR* var;
3731 	
3732 	      var = vars[v];
3733 	      assert(var != NULL);
3734 	
3735 	      if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3736 	         || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3737 	         return FALSE;
3738 	   }
3739 	
3740 	   return TRUE;
3741 	}
3742 	
3743 	/** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3744 	 *  (dual reductions)
3745 	 */
3746 	static
3747 	SCIP_RETCODE solveIndependentCons(
3748 	   SCIP*                 scip,               /**< SCIP data structure */
3749 	   SCIP_CONS*            cons,               /**< cumulative constraint */
3750 	   SCIP_Longint          maxnodes,           /**< number of branch-and-bound nodes to solve an independent cumulative constraint  (-1: no limit) */
3751 	   int*                  nchgbds,            /**< pointer to store the number changed variable bounds */
3752 	   int*                  nfixedvars,         /**< pointer to count number of fixings */
3753 	   int*                  ndelconss,          /**< pointer to count number of deleted constraints  */
3754 	   SCIP_Bool*            cutoff,             /**< pointer to store if the constraint is infeasible */
3755 	   SCIP_Bool*            unbounded           /**< pointer to store if the constraint is unbounded */
3756 	   )
3757 	{
3758 	   SCIP_CONSDATA* consdata;
3759 	   SCIP_VAR** vars;
3760 	   SCIP_Real* objvals;
3761 	   SCIP_Real* lbs;
3762 	   SCIP_Real* ubs;
3763 	   SCIP_Real timelimit;
3764 	   SCIP_Real memorylimit;
3765 	   SCIP_Bool solved;
3766 	   SCIP_Bool error;
3767 	
3768 	   int ncheckconss;
3769 	   int nvars;
3770 	   int v;
3771 	
3772 	   assert(scip != NULL);
3773 	   assert(!SCIPconsIsModifiable(cons));
3774 	   assert(SCIPgetNConss(scip) > 0);
3775 	
3776 	   /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3777 	    * would/could end in an implication which can lead to cutoff of the/all optimal solution
3778 	    */
3779 	   if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3780 	      return SCIP_OKAY;
3781 	
3782 	   /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3783 	    * use the locks to decide for a dual reduction using this constraint;
3784 	    */
3785 	   if( !SCIPconsIsChecked(cons) )
3786 	      return SCIP_OKAY;
3787 	
3788 	   ncheckconss = SCIPgetNCheckConss(scip);
3789 	
3790 	   /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3791 	    * presolved problem do nothing execpt to change the parameter settings
3792 	    */
3793 	   if( ncheckconss == 1 )
3794 	   {
3795 	      /* shrink the minimal maximum value for the conflict length */
3796 	      SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3797 	
3798 	      /* use only first unique implication point */
3799 	      SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3800 	
3801 	      /* do not use reconversion conflicts */
3802 	      SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3803 	
3804 	      /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3805 	      SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3806 	
3807 	      /* increase the number of conflicts which induce a restart */
3808 	      SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3809 	
3810 	      /* weight the variable which made into a conflict */
3811 	      SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3812 	
3813 	      /* do not check pseudo solution (for performance reasons) */
3814 	      SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3815 	
3816 	      /* use value based history to detect a reasonable branching point */
3817 	      SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3818 	
3819 	      /* turn of LP relaxation */
3820 	      SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3821 	
3822 	      /* prefer the down branch in case the value based history does not suggest something */
3823 	      SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3824 	
3825 	      /* accept any bound change */
3826 	      SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3827 	
3828 	      /* allow for at most 10 restart, after that the value based history should be reliable */
3829 	      SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3830 	
3831 	      /* set priority for depth first search to highest possible value */
3832 	      SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3833 	
3834 	      return SCIP_OKAY;
3835 	   }
3836 	
3837 	   consdata = SCIPconsGetData(cons);
3838 	   assert(consdata != NULL);
3839 	
3840 	   /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3841 	    * fail on the first place
3842 	    */
3843 	   if( consdata->triedsolving )
3844 	      return SCIP_OKAY;
3845 	
3846 	   /* check if constraint is independently */
3847 	   if( !isConsIndependently(cons) )
3848 	      return SCIP_OKAY;
3849 	
3850 	   /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3851 	    * constraint is deleted; otherwise, we want to ensure that we do not try that again
3852 	    */
3853 	   consdata->triedsolving = TRUE;
3854 	
3855 	   SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3856 	      SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3857 	   SCIPdebugPrintCons(scip, cons, NULL);
3858 	
3859 	   nvars = consdata->nvars;
3860 	   vars = consdata->vars;
3861 	
3862 	   SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3863 	   SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3864 	   SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3865 	
3866 	   for( v = 0; v < nvars; ++v )
3867 	   {
3868 	      SCIP_VAR* var;
3869 	
3870 	      /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3871 	       * array
3872 	       */
3873 	      var = vars[v];
3874 	      assert(var != NULL);
3875 	
3876 	      lbs[v] = SCIPvarGetLbLocal(var);
3877 	      ubs[v] = SCIPvarGetUbLocal(var);
3878 	
3879 	      objvals[v] = SCIPvarGetObj(var);
3880 	   }
3881 	
3882 	   /* check whether there is enough time and memory left */
3883 	   SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3884 	   if( !SCIPisInfinity(scip, timelimit) )
3885 	      timelimit -= SCIPgetSolvingTime(scip);
3886 	   SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3887 	
3888 	   /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3889 	   if( !SCIPisInfinity(scip, memorylimit) )
3890 	   {
3891 	      memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3892 	      memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3893 	   }
3894 	
3895 	   /* solve the cumulative condition separately */
3896 	   SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3897 	         consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3898 	
3899 	   if( !(*cutoff) && !(*unbounded) && !error )
3900 	   {
3901 	      SCIP_Bool infeasible;
3902 	      SCIP_Bool tightened;
3903 	      SCIP_Bool allfixed;
3904 	
3905 	      allfixed = TRUE;
3906 	
3907 	      for( v = 0; v < nvars; ++v )
3908 	      {
3909 	         /* check if variable is fixed */
3910 	         if( lbs[v] + 0.5 > ubs[v] )
3911 	         {
3912 	            SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3913 	            assert(!infeasible);
3914 	
3915 	            if( tightened )
3916 	            {
3917 	               (*nfixedvars)++;
3918 	               consdata->triedsolving = FALSE;
3919 	            }
3920 	         }
3921 	         else
3922 	         {
3923 	            SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3924 	            assert(!infeasible);
3925 	
3926 	            if( tightened )
3927 	            {
3928 	               (*nchgbds)++;
3929 	               consdata->triedsolving = FALSE;
3930 	            }
3931 	
3932 	            SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3933 	            assert(!infeasible);
3934 	
3935 	            if( tightened )
3936 	            {
3937 	               (*nchgbds)++;
3938 	               consdata->triedsolving = FALSE;
3939 	            }
3940 	
3941 	            allfixed = FALSE;
3942 	         }
3943 	      }
3944 	
3945 	      /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3946 	      if( allfixed )
3947 	      {
3948 	         SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3949 	         (*ndelconss)++;
3950 	      }
3951 	   }
3952 	
3953 	   SCIPfreeBufferArray(scip, &objvals);
3954 	   SCIPfreeBufferArray(scip, &ubs);
3955 	   SCIPfreeBufferArray(scip, &lbs);
3956 	
3957 	   return SCIP_OKAY;
3958 	}
3959 	
3960 	/** start conflict analysis to analysis the core insertion which is infeasible */
3961 	static
3962 	SCIP_RETCODE analyseInfeasibelCoreInsertion(
3963 	   SCIP*                 scip,               /**< SCIP data structure */
3964 	   int                   nvars,              /**< number of start time variables (activities) */
3965 	   SCIP_VAR**            vars,               /**< array of start time variables */
3966 	   int*                  durations,          /**< array of durations */
3967 	   int*                  demands,            /**< array of demands */
3968 	   int                   capacity,           /**< cumulative capacity */
3969 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
3970 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
3971 	   SCIP_VAR*             infervar,           /**< start time variable which lead to the infeasibilty */
3972 	   int                   inferduration,      /**< duration of the start time variable */
3973 	   int                   inferdemand,        /**< demand of the start time variable */
3974 	   int                   inferpeak,          /**< profile preak which causes the infeasibilty */
3975 	   SCIP_Bool             usebdwidening,      /**< should bound widening be used during conflict analysis? */
3976 	   SCIP_Bool*            initialized,        /**< pointer to store if the conflict analysis was initialized */
3977 	   SCIP_Bool*            explanation         /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3978 	   )
3979 	{
3980 	   SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3981 	   SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3982 	      SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3983 	
3984 	   /* initialize conflict analysis if conflict analysis is applicable */
3985 	   if( SCIPisConflictAnalysisApplicable(scip) )
3986 	   {
3987 	      SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
3988 	
3989 	      SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3990 	            infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3991 	
3992 	      SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3993 	
3994 	      /* add both bound of the inference variable since these biuld the core which we could not inserted */
3995 	      if( usebdwidening )
3996 	      {
3997 	         SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3998 	         SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL,  (SCIP_Real)inferpeak) );
3999 	      }
4000 	      else
4001 	      {
4002 	         SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
4003 	         SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
4004 	      }
4005 	
4006 	      *initialized = TRUE;
4007 	   }
4008 	
4009 	   return SCIP_OKAY;
4010 	}
4011 	
4012 	/** We are using the core resource profile which contains all core except the one of the start time variable which we
4013 	 *  want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
4014 	 *  the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4015 	 *  analysis
4016 	 */
4017 	static
4018 	SCIP_RETCODE coretimesUpdateLb(
4019 	   SCIP*                 scip,               /**< SCIP data structure */
4020 	   int                   nvars,              /**< number of start time variables (activities) */
4021 	   SCIP_VAR**            vars,               /**< array of start time variables */
4022 	   int*                  durations,          /**< array of durations */
4023 	   int*                  demands,            /**< array of demands */
4024 	   int                   capacity,           /**< cumulative capacity */
4025 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
4026 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
4027 	   SCIP_CONS*            cons,               /**< constraint which is propagated */
4028 	   SCIP_PROFILE*         profile,            /**< resource profile */
4029 	   int                   idx,                /**< position of the variable to propagate */
4030 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
4031 	   SCIP_Bool             usebdwidening,      /**< should bound widening be used during conflict analysis? */
4032 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
4033 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4034 	   SCIP_Bool*            infeasible          /**< pointer to store if the constraint is infeasible */
4035 	   )
4036 	{
4037 	   SCIP_VAR* var;
4038 	   int ntimepoints;
4039 	   int duration;
4040 	   int demand;
4041 	   int peak;
4042 	   int newlb;
4043 	   int est;
4044 	   int lst;
4045 	   int pos;
4046 	
4047 	   var = vars[idx];
4048 	   assert(var != NULL);
4049 	
4050 	   duration = durations[idx];
4051 	   assert(duration > 0);
4052 	
4053 	   demand = demands[idx];
4054 	   assert(demand > 0);
4055 	
4056 	   est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4057 	   lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4058 	   ntimepoints = SCIPprofileGetNTimepoints(profile);
4059 	
4060 	   /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4061 	    * load which we have at the earliest start time (lower bound)
4062 	    */
4063 	   (void) SCIPprofileFindLeft(profile, est, &pos);
4064 	
4065 	   SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4066 	
4067 	   /* we now trying to move the earliest start time in steps of at most "duration" length */
4068 	   do
4069 	   {
4070 	      INFERINFO inferinfo;
4071 	      SCIP_Bool tightened;
4072 	      int ect;
4073 	
4074 	#ifndef NDEBUG
4075 	      {
4076 	         /* in debug mode we check that we adjust the search position correctly */
4077 	         int tmppos;
4078 	
4079 	         (void)SCIPprofileFindLeft(profile, est, &tmppos);
4080 	         assert(pos == tmppos);
4081 	      }
4082 	#endif
4083 	      ect = est + duration;
4084 	      peak = -1;
4085 	
4086 	      /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4087 	       * want a peak which is closest to the earliest completion time
4088 	       */
4089 	      do
4090 	      {
4091 	         /* check if the profile load conflicts with the demand of the start time variable */
4092 	         if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4093 	            peak = pos;
4094 	
4095 	         pos++;
4096 	      }
4097 	      while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4098 	
4099 	      /* if we found no peak that means current the job could be scheduled at its earliest start time without
4100 	       * conflicting to the core resource profile
4101 	       */
4102 	      /* coverity[check_after_sink] */
4103 	      if( peak == -1 )
4104 	         break;
4105 	
4106 	      /* the peak position gives us a time point where the start time variable is in conflict with the resource
4107 	       * profile. That means we have to move it to the next time point in the resource profile but at most to the
4108 	       * earliest completion time (the remaining move will done in the next loop)
4109 	       */
4110 	      newlb = SCIPprofileGetTime(profile, peak+1);
4111 	      newlb = MIN(newlb, ect);
4112 	
4113 	      /* if the earliest start time is greater than the lst we detected an infeasibilty */
4114 	      if( newlb > lst )
4115 	      {
4116 	         SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4117 	
4118 	         /* use conflict analysis to analysis the core insertion which was infeasible */
4119 	         SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4120 	               var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4121 	
4122 	         if( explanation != NULL )
4123 	            explanation[idx] = TRUE;
4124 	
4125 	         *infeasible = TRUE;
4126 	
4127 	         break;
4128 	      }
4129 	
4130 	      /* construct the inference information which we are using with the conflict analysis to resolve that particular
4131 	       * bound change
4132 	       */
4133 	      inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4134 	
4135 	      /* perform the bound lower bound change */
4136 	      if( inferInfoIsValid(inferinfo) )
4137 	      {
4138 	         SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4139 	      }
4140 	      else
4141 	      {
4142 	         SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4143 	      }
4144 	      assert(tightened);
4145 	      assert(!(*infeasible));
4146 	
4147 	      SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4148 	      (*nchgbds)++;
4149 	
4150 	      /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4151 	      SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nlbtimetable++ );
4152 	
4153 	      /* adjust the earliest start time
4154 	       *
4155 	       * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4156 	       *       the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4157 	       *       involved.
4158 	       */
4159 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4160 	      assert(est >= newlb);
4161 	
4162 	      /* adjust the search position for the resource profile for the next step */
4163 	      if( est == SCIPprofileGetTime(profile, peak+1) )
4164 	         pos = peak + 1;
4165 	      else
4166 	         pos = peak;
4167 	   }
4168 	   while( est < lst );
4169 	
4170 	   return SCIP_OKAY;
4171 	}
4172 	
4173 	/** We are using the core resource profile which contains all core except the one of the start time variable which we
4174 	 *  want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4175 	 *  the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4176 	 *  analysis
4177 	 */
4178 	static
4179 	SCIP_RETCODE coretimesUpdateUb(
4180 	   SCIP*                 scip,               /**< SCIP data structure */
4181 	   SCIP_VAR*             var,                /**< start time variable to propagate */
4182 	   int                   duration,           /**< duration of the job */
4183 	   int                   demand,             /**< demand of the job */
4184 	   int                   capacity,           /**< cumulative capacity */
4185 	   SCIP_CONS*            cons,               /**< constraint which is propagated */
4186 	   SCIP_PROFILE*         profile,            /**< resource profile */
4187 	   int                   idx,                /**< position of the variable to propagate */
4188 	   int*                  nchgbds             /**< pointer to store the number of bound changes */
4189 	   )
4190 	{
4191 	   int ntimepoints;
4192 	   int newub;
4193 	   int peak;
4194 	   int pos;
4195 	   int est;
4196 	   int lst;
4197 	   int lct;
4198 	
4199 	   assert(var != NULL);
4200 	   assert(duration > 0);
4201 	   assert(demand > 0);
4202 	
4203 	   est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4204 	   lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4205 	
4206 	   /* in case the start time variable is fixed do nothing */
4207 	   if( est == lst )
4208 	      return SCIP_OKAY;
4209 	
4210 	   ntimepoints = SCIPprofileGetNTimepoints(profile);
4211 	
4212 	   lct = lst + duration;
4213 	
4214 	   /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4215 	    * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4216 	    * position gives us the load which we have at the latest completion time minus one
4217 	    */
4218 	   (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4219 	
4220 	   SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4221 	   SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4222 	
4223 	   if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4224 	      return SCIP_OKAY;
4225 	
4226 	   /* we now trying to move the latest start time in steps of at most "duration" length */
4227 	   do
4228 	   {
4229 	      INFERINFO inferinfo;
4230 	      SCIP_Bool tightened;
4231 	      SCIP_Bool infeasible;
4232 	
4233 	      peak = -1;
4234 	
4235 	#ifndef NDEBUG
4236 	      {
4237 	         /* in debug mode we check that we adjust the search position correctly */
4238 	         int tmppos;
4239 	
4240 	         (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4241 	         assert(pos == tmppos);
4242 	      }
4243 	#endif
4244 	
4245 	      /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4246 	       * want a peak which is closest to the latest start time
4247 	       */
4248 	      do
4249 	      {
4250 	         if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4251 	            peak = pos;
4252 	
4253 	         pos--;
4254 	      }
4255 	      while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4256 	
4257 	      /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4258 	       * to the core resource profile
4259 	       */
4260 	      /* coverity[check_after_sink] */
4261 	      if( peak == -1 )
4262 	         break;
4263 	
4264 	      /* the peak position gives us a time point where the start time variable is in conflict with the resource
4265 	       * profile. That means the job has be done until that point. Hence that gives us the latest completion
4266 	       * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4267 	       * doing in the next loop)
4268 	       */
4269 	      newub = SCIPprofileGetTime(profile, peak);
4270 	      newub = MAX(newub, lst) - duration;
4271 	      assert(newub >= est);
4272 	
4273 	      /* construct the inference information which we are using with the conflict analysis to resolve that particular
4274 	       * bound change
4275 	       */
4276 	      inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4277 	
4278 	      /* perform the bound upper bound change */
4279 	      if( inferInfoIsValid(inferinfo) )
4280 	      {
4281 	         SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4282 	      }
4283 	      else
4284 	      {
4285 	         SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4286 	      }
4287 	      assert(tightened);
4288 	      assert(!infeasible);
4289 	
4290 	      SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4291 	      (*nchgbds)++;
4292 	
4293 	      /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4294 	      SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nubtimetable++ );
4295 	
4296 	      /* adjust the latest start and completion time
4297 	       *
4298 	       * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4299 	       *       the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4300 	       *       involved.
4301 	       */
4302 	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4303 	      assert(lst <= newub);
4304 	      lct = lst + duration;
4305 	
4306 	      /* adjust the search position for the resource profile for the next step */
4307 	      if( SCIPprofileGetTime(profile, peak) == lct )
4308 	         pos = peak - 1;
4309 	      else
4310 	         pos = peak;
4311 	   }
4312 	   while( est < lst );
4313 	
4314 	   return SCIP_OKAY;
4315 	}
4316 	
4317 	/** compute for the different earliest start and latest completion time the core energy of the corresponding time
4318 	 *  points
4319 	 */
4320 	static
4321 	void computeCoreEnergyAfter(
4322 	   SCIP_PROFILE*         profile,            /**< core profile */
4323 	   int                   nvars,              /**< number of start time variables (activities) */
4324 	   int*                  ests,               /**< array of sorted earliest start times */
4325 	   int*                  lcts,               /**< array of sorted latest completion times */
4326 	   int*                  coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4327 	   int*                  coreEnergyAfterLct  /**< array to store the core energy after the latest completion time of each job */
4328 	   )
4329 	{
4330 	   int ntimepoints;
4331 	   int energy;
4332 	   int t;
4333 	   int v;
4334 	
4335 	   ntimepoints = SCIPprofileGetNTimepoints(profile);
4336 	   t = ntimepoints - 1;
4337 	   energy = 0;
4338 	
4339 	   /* compute core energy after the earliest start time of each job */
4340 	   for( v = nvars-1; v >= 0; --v )
4341 	   {
4342 	      while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4343 	      {
4344 	         assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4345 	         assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4346 	         energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4347 	         t--;
4348 	      }
4349 	      assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4350 	
4351 	      /* maybe ests[j] is in-between two timepoints */
4352 	      if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4353 	      {
4354 	         assert(t > 0);
4355 	         coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4356 	      }
4357 	      else
4358 	         coreEnergyAfterEst[v] = energy;
4359 	   }
4360 	
4361 	   t = ntimepoints - 1;
4362 	   energy = 0;
4363 	
4364 	   /* compute core energy after the latest completion time of each job */
4365 	   for( v = nvars-1; v >= 0; --v )
4366 	   {
4367 	      while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4368 	      {
4369 	         assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4370 	         assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4371 	         energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4372 	         t--;
4373 	      }
4374 	      assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4375 	
4376 	      /* maybe lcts[j] is in-between two timepoints */
4377 	      if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4378 	      {
4379 	         assert(t > 0);
4380 	         coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4381 	      }
4382 	      else
4383 	         coreEnergyAfterLct[v] = energy;
4384 	   }
4385 	}
4386 	
4387 	/** collect earliest start times, latest completion time, and free energy contributions */
4388 	static
4389 	void collectDataTTEF(
4390 	   SCIP*                 scip,               /**< SCIP data structure */
4391 	   int                   nvars,              /**< number of start time variables (activities) */
4392 	   SCIP_VAR**            vars,               /**< array of start time variables */
4393 	   int*                  durations,          /**< array of durations */
4394 	   int*                  demands,            /**< array of demands */
4395 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
4396 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
4397 	   int*                  permests,           /**< array to store the variable positions */
4398 	   int*                  ests,               /**< array to store earliest start times */
4399 	   int*                  permlcts,           /**< array to store the variable positions */
4400 	   int*                  lcts,               /**< array to store latest completion times */
4401 	   int*                  ects,               /**< array to store earliest completion times of the flexible part of the job */
4402 	   int*                  lsts,               /**< array to store latest start times of the flexible part of the job */
4403 	   int*                  flexenergies        /**< array to store the flexible energies of each job */
4404 	   )
4405 	{
4406 	   int v;
4407 	
4408 	   for( v = 0; v < nvars; ++ v)
4409 	   {
4410 	      int duration;
4411 	      int leftadjust;
4412 	      int rightadjust;
4413 	      int core;
4414 	      int est;
4415 	      int lct;
4416 	      int ect;
4417 	      int lst;
4418 	
4419 	      duration = durations[v];
4420 	      assert(duration > 0);
4421 	
4422 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4423 	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4424 	      ect = est + duration;
4425 	      lct = lst + duration;
4426 	
4427 	      ests[v] = est;
4428 	      lcts[v] = lct;
4429 	      permests[v] = v;
4430 	      permlcts[v] = v;
4431 	
4432 	      /* compute core time window which lies within the effective horizon */
4433 	      core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4434 	
4435 	      /* compute the number of time steps the job could run before the effective horizon */
4436 	      leftadjust = MAX(0, hmin - est);
4437 	
4438 	      /* compute the number of time steps the job could run after the effective horizon */
4439 	      rightadjust = MAX(0, lct - hmax);
4440 	
4441 	      /* compute for each job the energy which is flexible; meaning not part of the core */
4442 	      flexenergies[v] = duration - leftadjust - rightadjust - core;
4443 	      flexenergies[v] = MAX(0, flexenergies[v]);
4444 	      flexenergies[v] *= demands[v];
4445 	      assert(flexenergies[v] >= 0);
4446 	
4447 	      /* the earliest completion time of the flexible energy */
4448 	      ects[v] = MIN(ect, lst);
4449 	
4450 	      /* the latest start time of the flexible energy */
4451 	      lsts[v] = MAX(ect, lst);
4452 	   }
4453 	}
4454 	
4455 	/** try to tighten the lower bound of the given variable */
4456 	static
4457 	SCIP_RETCODE tightenLbTTEF(
4458 	   SCIP*                 scip,               /**< SCIP data structure */
4459 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
4460 	   int                   nvars,              /**< number of start time variables (activities) */
4461 	   SCIP_VAR**            vars,               /**< array of start time variables */
4462 	   int*                  durations,          /**< array of durations */
4463 	   int*                  demands,            /**< array of demands */
4464 	   int                   capacity,           /**< cumulative capacity */
4465 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
4466 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
4467 	   SCIP_VAR*             var,                /**< variable to be considered for upper bound tightening */
4468 	   int                   duration,           /**< duration of the job */
4469 	   int                   demand,             /**< demand of the job */
4470 	   int                   est,                /**< earliest start time of the job */
4471 	   int                   ect,                /**< earliest completion time of the flexible part of the job */
4472 	   int                   lct,                /**< latest completion time of the job */
4473 	   int                   begin,              /**< begin of the time window under investigation */
4474 	   int                   end,                /**< end of the time window under investigation */
4475 	   SCIP_Longint          energy,             /**< available energy for the flexible part of the hob within the time window */
4476 	   int*                  bestlb,             /**< pointer to strope the best lower bound change */
4477 	   int*                  inferinfos,         /**< pointer to store the inference information which is need for the (best) lower bound change */
4478 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
4479 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4480 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
4481 	   )
4482 	{
4483 	   int newlb;
4484 	
4485 	   assert(begin >= hmin);
4486 	   assert(end <= hmax);
4487 	
4488 	   /* check if the time-table edge-finding should infer bounds */
4489 	   if( !conshdlrdata->ttefinfer )
4490 	      return SCIP_OKAY;
4491 	
4492 	   /* if the job can be processed completely before or after the time window, nothing can be tightened */
4493 	   if( est >= end || ect <= begin )
4494 	      return SCIP_OKAY;
4495 	
4496 	   /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4497 	    * skip since the overload check will do the job
4498 	    */
4499 	   if( est >= begin && ect <= end )
4500 	      return SCIP_OKAY;
4501 	
4502 	   /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4503 	    * earliest start time
4504 	    */
4505 	   if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4506 	      return SCIP_OKAY;
4507 	
4508 	   /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4509 	    * present; therefore, we need to add the core;
4510 	    *
4511 	    * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4512 	    *       compute the earliest completion time of the (whole) job
4513 	    */
4514 	   energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4515 	
4516 	   /* compute a latest start time (upper bound) such that the job consums at most the available energy
4517 	    *
4518 	    * @note we can round down the compute duration w.r.t. the available energy
4519 	    */
4520 	   newlb = end - (int) (energy / demand);
4521 	
4522 	   /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4523 	    * bound (latest start time); meaning it is not possible to schedule the job
4524 	    */
4525 	   if( newlb > lct - duration )
4526 	   {
4527 	      /* initialize conflict analysis if conflict analysis is applicable */
4528 	      if( SCIPisConflictAnalysisApplicable(scip) )
4529 	      {
4530 	         SCIP_Real relaxedbd;
4531 	
4532 	         assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4533 	
4534 	         /* it is enough to overshoot the upper bound of the variable by one */
4535 	         relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4536 	
4537 	         /* initialize conflict analysis */
4538 	         SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
4539 	
4540 	         /* added to upper bound (which was overcut be new lower bound) of the variable */
4541 	         SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4542 	
4543 	         /* analyze the infeasible */
4544 	         SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4545 	               begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4546 	
4547 	         (*initialized) = TRUE;
4548 	      }
4549 	
4550 	      (*cutoff) = TRUE;
4551 	   }
4552 	   else if( newlb > (*bestlb) )
4553 	   {
4554 	      INFERINFO inferinfo;
4555 	
4556 	      assert(newlb > begin);
4557 	
4558 	      inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4559 	
4560 	      /* construct inference information */
4561 	      (*inferinfos) = inferInfoToInt(inferinfo);
4562 	      (*bestlb) = newlb;
4563 	   }
4564 	
4565 	   return SCIP_OKAY;
4566 	}
4567 	
4568 	/** try to tighten the upper bound of the given variable */
4569 	static
4570 	SCIP_RETCODE tightenUbTTEF(
4571 	   SCIP*                 scip,               /**< SCIP data structure */
4572 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
4573 	   int                   nvars,              /**< number of start time variables (activities) */
4574 	   SCIP_VAR**            vars,               /**< array of start time variables */
4575 	   int*                  durations,          /**< array of durations */
4576 	   int*                  demands,            /**< array of demands */
4577 	   int                   capacity,           /**< cumulative capacity */
4578 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
4579 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
4580 	   SCIP_VAR*             var,                /**< variable to be considered for upper bound tightening */
4581 	   int                   duration,           /**< duration of the job */
4582 	   int                   demand,             /**< demand of the job */
4583 	   int                   est,                /**< earliest start time of the job */
4584 	   int                   lst,                /**< latest start time of the flexible part of the job */
4585 	   int                   lct,                /**< latest completion time of the job */
4586 	   int                   begin,              /**< begin of the time window under investigation */
4587 	   int                   end,                /**< end of the time window under investigation */
4588 	   SCIP_Longint          energy,             /**< available energy for the flexible part of the hob within the time window */
4589 	   int*                  bestub,             /**< pointer to strope the best upper bound change */
4590 	   int*                  inferinfos,         /**< pointer to store the inference information which is need for the (best) upper bound change */
4591 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
4592 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4593 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
4594 	   )
4595 	{
4596 	   int newub;
4597 	
4598 	   assert(begin >= hmin);
4599 	   assert(end <= hmax);
4600 	   assert(est < begin);
4601 	
4602 	   /* check if the time-table edge-finding should infer bounds */
4603 	   if( !conshdlrdata->ttefinfer )
4604 	      return SCIP_OKAY;
4605 	
4606 	   /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4607 	   if( lst >= end || lct <= begin )
4608 	      return SCIP_OKAY;
4609 	
4610 	   /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4611 	    * skip since the overload check will do the job
4612 	    */
4613 	   if( lst >= begin && lct <= end )
4614 	      return SCIP_OKAY;
4615 	
4616 	   /* check if the available energy in the time window is to small to handle the flexible part  of the job */
4617 	   if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4618 	      return SCIP_OKAY;
4619 	
4620 	   /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4621 	    * present; therefore, we need to add the core;
4622 	    *
4623 	    * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4624 	    *       latest start of the (whole) job
4625 	    */
4626 	   energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4627 	   assert(energy >= 0);
4628 	
4629 	   /* compute a latest start time (upper bound) such that the job consums at most the available energy
4630 	    *
4631 	    * @note we can round down the compute duration w.r.t. the available energy
4632 	    */
4633 	   assert(demand > 0);
4634 	   newub = begin - duration + (int) (energy / demand);
4635 	
4636 	   /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4637 	    * bound (earliest start time); meaning it is not possible to schedule the job
4638 	    */
4639 	   if( newub < est )
4640 	   {
4641 	      /* initialize conflict analysis if conflict analysis is applicable */
4642 	      if( SCIPisConflictAnalysisApplicable(scip) )
4643 	      {
4644 	         SCIP_Real relaxedbd;
4645 	
4646 	         assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4647 	
4648 	         /* it is enough to undershoot the lower bound of the variable by one */
4649 	         relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4650 	
4651 	         /* initialize conflict analysis */
4652 	         SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
4653 	
4654 	         /* added to lower bound (which was undercut be new upper bound) of the variable */
4655 	         SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4656 	
4657 	         /* analyze the infeasible */
4658 	         SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4659 	               begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4660 	
4661 	         (*initialized) = TRUE;
4662 	      }
4663 	
4664 	      (*cutoff) = TRUE;
4665 	   }
4666 	   else if( newub < (*bestub) )
4667 	   {
4668 	      INFERINFO inferinfo;
4669 	
4670 	      assert(newub < begin);
4671 	
4672 	      inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4673 	
4674 	      /* construct inference information */
4675 	      (*inferinfos) = inferInfoToInt(inferinfo);
4676 	      (*bestub) = newub;
4677 	   }
4678 	
4679 	   return SCIP_OKAY;
4680 	}
4681 	
4682 	/** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4683 	static
4684 	SCIP_RETCODE propagateUbTTEF(
4685 	   SCIP*                 scip,               /**< SCIP data structure */
4686 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
4687 	   int                   nvars,              /**< number of start time variables (activities) */
4688 	   SCIP_VAR**            vars,               /**< array of start time variables */
4689 	   int*                  durations,          /**< array of durations */
4690 	   int*                  demands,            /**< array of demands */
4691 	   int                   capacity,           /**< cumulative capacity */
4692 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
4693 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
4694 	   int*                  newlbs,             /**< array to buffer new lower bounds */
4695 	   int*                  newubs,             /**< array to buffer new upper bounds */
4696 	   int*                  lbinferinfos,       /**< array to store the inference information for the lower bound changes */
4697 	   int*                  ubinferinfos,       /**< array to store the inference information for the upper bound changes */
4698 	   int*                  lsts,               /**< array of latest start time of the flexible part in the same order as the variables */
4699 	   int*                  flexenergies,       /**< array of flexible energies in the same order as the variables */
4700 	   int*                  perm,               /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4701 	   int*                  ests,               /**< array with earliest strart times sorted in non-decreasing order */
4702 	   int*                  lcts,               /**< array with latest completion times sorted in non-decreasing order */
4703 	   int*                  coreEnergyAfterEst, /**< core energy after the earliest start times */
4704 	   int*                  coreEnergyAfterLct, /**< core energy after the latest completion times */
4705 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
4706 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4707 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
4708 	   )
4709 	{
4710 	   int coreEnergyAfterEnd;
4711 	   SCIP_Longint maxavailable;
4712 	   SCIP_Longint minavailable;
4713 	   SCIP_Longint totalenergy;
4714 	   int nests;
4715 	   int est;
4716 	   int lct;
4717 	   int start;
4718 	   int end;
4719 	   int v;
4720 	
4721 	   est = INT_MAX;
4722 	   lct = INT_MIN;
4723 	
4724 	   /* compute earliest start and latest completion time of all jobs */
4725 	   for( v = 0; v < nvars; ++v )
4726 	   {
4727 	      start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4728 	      end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4729 	
4730 	      est = MIN(est, start);
4731 	      lct = MAX(lct, end);
4732 	   }
4733 	
4734 	   /* adjust the effective time horizon */
4735 	   hmin = MAX(hmin, est);
4736 	   hmax = MIN(hmax, lct);
4737 	
4738 	   end = hmax + 1;
4739 	   coreEnergyAfterEnd = -1;
4740 	
4741 	   maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4742 	   minavailable = maxavailable;
4743 	   totalenergy = computeTotalEnergy(durations, demands, nvars);
4744 	
4745 	   /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4746 	   if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4747 	      return SCIP_OKAY;
4748 	
4749 	   nests = nvars;
4750 	
4751 	   /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4752 	    * times define the end of the time interval under investigation
4753 	    */
4754 	   for( v = nvars-1; v >= 0  && !(*cutoff); --v )
4755 	   {
4756 	      int flexenergy;
4757 	      int minbegin;
4758 	      int lbenergy;
4759 	      int lbcand;
4760 	      int i;
4761 	
4762 	      lct = lcts[v];
4763 	
4764 	      /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4765 	       * infinity capacity is available; hence we skip that
4766 	       */
4767 	      if( lct > hmax )
4768 	         continue;
4769 	
4770 	      /* if the latest completion time is smaller then hmin we have to stop */
4771 	      if( lct <= hmin )
4772 	      {
4773 	         assert(v == 0 || lcts[v-1] <= lcts[v]);
4774 	         break;
4775 	      }
4776 	
4777 	      /* if the latest completion time equals to previous end time, we can continue since this particular interval
4778 	       * induced by end was just analyzed
4779 	       */
4780 	      if( lct == end )
4781 	         continue;
4782 	
4783 	      assert(lct < end);
4784 	
4785 	      /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4786 	       * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4787 	       * free energy; if so it means that in the next iterate the free-energy cannot be negative
4788 	       */
4789 	      if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4790 	      {
4791 	         SCIP_Longint freeenergy;
4792 	
4793 	         assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4794 	         assert(coreEnergyAfterEnd >= 0);
4795 	
4796 	         /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4797 	         freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4798 	
4799 	         if( freeenergy <= minavailable )
4800 	         {
4801 	            SCIPdebugMsg(scip, "skip latest completion time  <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4802 	            continue;
4803 	         }
4804 	      }
4805 	
4806 	      SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4807 	
4808 	      end = lct;
4809 	      coreEnergyAfterEnd = coreEnergyAfterLct[v];
4810 	
4811 	      flexenergy = 0;
4812 	      minavailable = maxavailable;
4813 	      minbegin = hmax;
4814 	      lbcand = -1;
4815 	      lbenergy = 0;
4816 	
4817 	      /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4818 	       * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4819 	       * wider
4820 	       */
4821 	      for( i = nests-1; i >= 0; --i )
4822 	      {
4823 	         SCIP_VAR* var;
4824 	         SCIP_Longint freeenergy;
4825 	         int duration;
4826 	         int demand;
4827 	         int begin;
4828 	         int idx;
4829 	         int lst;
4830 	
4831 	         idx = perm[i];
4832 	         assert(idx >= 0);
4833 	         assert(idx < nvars);
4834 	         assert(!(*cutoff));
4835 	
4836 	         /* the earliest start time of the job */
4837 	         est = ests[i];
4838 	
4839 	         /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4840 	          * latest completion times (which define end) are scant in non-increasing order
4841 	          */
4842 	         if( end <= est )
4843 	         {
4844 	            nests--;
4845 	            continue;
4846 	         }
4847 	
4848 	         /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4849 	          * current ending time
4850 	          */
4851 	         if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4852 	            break;
4853 	
4854 	         var = vars[idx];
4855 	         assert(var != NULL);
4856 	
4857 	         duration = durations[idx];
4858 	         assert(duration > 0);
4859 	
4860 	         demand = demands[idx];
4861 	         assert(demand > 0);
4862 	
4863 	         lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4864 	
4865 	         /* the latest start time of the free part of the job */
4866 	         lst = lsts[idx];
4867 	
4868 	         /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4869 	          * investigation; hence the overload check will do the the job
4870 	          */
4871 	         assert(est <= minbegin);
4872 	         if( minavailable < maxavailable && est < minbegin )
4873 	         {
4874 	            assert(!(*cutoff));
4875 	
4876 	            /* try to tighten the upper bound */
4877 	            SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4878 	                  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4879 	                  initialized, explanation, cutoff) );
4880 	
4881 	            if( *cutoff )
4882 	               break;
4883 	         }
4884 	
4885 	         SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4886 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4887 	
4888 	         begin = est;
4889 	         assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4890 	
4891 	         /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4892 	          * free energy
4893 	          */
4894 	         if( begin < hmin )
4895 	            break;
4896 	
4897 	         /* compute the contribution to the flexible energy */
4898 	         if( lct <= end )
4899 	         {
4900 	            /* if the jobs has to finish before the end, all the energy has to be scheduled */
4901 	            assert(lst >= begin);
4902 	            assert(flexenergies[idx] >= 0);
4903 	            flexenergy += flexenergies[idx];
4904 	         }
4905 	         else
4906 	         {
4907 	            /* the job partly overlaps with the end */
4908 	            int candenergy;
4909 	            int energy;
4910 	
4911 	            /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4912 	             * w.r.t. latest start time
4913 	             *
4914 	             * @note we need to be aware of the effective horizon
4915 	             */
4916 	            energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4917 	            assert(end - lst < duration);
4918 	            assert(energy >= 0);
4919 	
4920 	            /* adjust the flexible energy of the time interval */
4921 	            flexenergy += energy;
4922 	
4923 	            /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4924 	            candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4925 	            assert(candenergy >= 0);
4926 	
4927 	            /* check if we found a better candidate */
4928 	            if( candenergy > lbenergy )
4929 	            {
4930 	               lbenergy = candenergy;
4931 	               lbcand = idx;
4932 	            }
4933 	         }
4934 	
4935 	         SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4936 	         assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4937 	
4938 	         /* compute the energy which is not used yet */
4939 	         freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4940 	
4941 	         /* check overload */
4942 	         if( freeenergy < 0 )
4943 	         {
4944 	            SCIPdebugMsg(scip, "analyze overload  within time window [%d,%d) capacity %d\n", begin, end, capacity);
4945 	
4946 	            /* initialize conflict analysis if conflict analysis is applicable */
4947 	            if( SCIPisConflictAnalysisApplicable(scip) )
4948 	            {
4949 	               /* analyze infeasibilty */
4950 	               SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
4951 	
4952 	               SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4953 	                     begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4954 	                     conshdlrdata->usebdwidening, explanation) );
4955 	
4956 	               (*initialized) = TRUE;
4957 	            }
4958 	
4959 	            (*cutoff) = TRUE;
4960 	
4961 	            /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4962 	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4963 	
4964 	            break;
4965 	         }
4966 	
4967 	         /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4968 	         if( lbenergy > 0 && freeenergy < lbenergy )
4969 	         {
4970 	            SCIP_Longint energy;
4971 	            int newlb;
4972 	            int ect;
4973 	
4974 	            ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4975 	            lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4976 	
4977 	            /* remove the energy of our job from the ... */
4978 	            energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4979 	
4980 	            newlb = end - (int)(energy / demands[lbcand]);
4981 	
4982 	            if( newlb > lst )
4983 	            {
4984 	               /* initialize conflict analysis if conflict analysis is applicable */
4985 	               if( SCIPisConflictAnalysisApplicable(scip) )
4986 	               {
4987 	                  SCIP_Real relaxedbd;
4988 	
4989 	                  /* analyze infeasibilty */
4990 	                  SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
4991 	
4992 	                  relaxedbd = lst + 1.0;
4993 	
4994 	                  /* added to upper bound (which was overcut be new lower bound) of the variable */
4995 	                  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4996 	
4997 	                  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4998 	                        begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4999 	                        conshdlrdata->usebdwidening, explanation) );
5000 	
5001 	                  (*initialized) = TRUE;
5002 	               }
5003 	
5004 	               (*cutoff) = TRUE;
5005 	               break;
5006 	            }
5007 	            else if( newlb > newlbs[lbcand] )
5008 	            {
5009 	               INFERINFO inferinfo;
5010 	
5011 	               /* construct inference information */
5012 	               inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5013 	
5014 	               /* buffer upper bound change */
5015 	               lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
5016 	               newlbs[lbcand] = newlb;
5017 	            }
5018 	         }
5019 	
5020 	         /* check if the current interval has a smaller free energy */
5021 	         if( minavailable > freeenergy )
5022 	         {
5023 	            minavailable = freeenergy;
5024 	            minbegin = begin;
5025 	         }
5026 	         assert(minavailable >= 0);
5027 	      }
5028 	   }
5029 	
5030 	   return SCIP_OKAY;
5031 	}
5032 	
5033 	/** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
5034 	static
5035 	SCIP_RETCODE propagateLbTTEF(
5036 	   SCIP*                 scip,               /**< SCIP data structure */
5037 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
5038 	   int                   nvars,              /**< number of start time variables (activities) */
5039 	   SCIP_VAR**            vars,               /**< array of start time variables */
5040 	   int*                  durations,          /**< array of durations */
5041 	   int*                  demands,            /**< array of demands */
5042 	   int                   capacity,           /**< cumulative capacity */
5043 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
5044 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
5045 	   int*                  newlbs,             /**< array to buffer new lower bounds */
5046 	   int*                  newubs,             /**< array to buffer new upper bounds */
5047 	   int*                  lbinferinfos,       /**< array to store the inference information for the lower bound changes */
5048 	   int*                  ubinferinfos,       /**< array to store the inference information for the upper bound changes */
5049 	   int*                  ects,               /**< array of earliest completion time of the flexible part in the same order as the variables */
5050 	   int*                  flexenergies,       /**< array of flexible energies in the same order as the variables */
5051 	   int*                  perm,               /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5052 	   int*                  ests,               /**< array with earliest strart times sorted in non-decreasing order */
5053 	   int*                  lcts,               /**< array with latest completion times sorted in non-decreasing order */
5054 	   int*                  coreEnergyAfterEst, /**< core energy after the earliest start times */
5055 	   int*                  coreEnergyAfterLct, /**< core energy after the latest completion times */
5056 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
5057 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5058 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
5059 	   )
5060 	{
5061 	   int coreEnergyAfterStart;
5062 	   SCIP_Longint maxavailable;
5063 	   SCIP_Longint minavailable;
5064 	   SCIP_Longint totalenergy;
5065 	   int nlcts;
5066 	   int begin;
5067 	   int minest;
5068 	   int maxlct;
5069 	   int start;
5070 	   int end;
5071 	   int v;
5072 	
5073 	   if( *cutoff )
5074 	      return SCIP_OKAY;
5075 	
5076 	   begin = hmin - 1;
5077 	
5078 	   minest = INT_MAX;
5079 	   maxlct = INT_MIN;
5080 	
5081 	   /* compute earliest start and latest completion time of all jobs */
5082 	   for( v = 0; v < nvars; ++v )
5083 	   {
5084 	      start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5085 	      end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5086 	
5087 	      minest = MIN(minest, start);
5088 	      maxlct = MAX(maxlct, end);
5089 	   }
5090 	
5091 	   /* adjust the effective time horizon */
5092 	   hmin = MAX(hmin, minest);
5093 	   hmax = MIN(hmax, maxlct);
5094 	
5095 	   maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5096 	   totalenergy = computeTotalEnergy(durations, demands, nvars);
5097 	
5098 	   /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5099 	   if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5100 	      return SCIP_OKAY;
5101 	
5102 	   nlcts = 0;
5103 	
5104 	   /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5105 	    * define the start of the time interval under investigation
5106 	    */
5107 	   for( v = 0; v < nvars; ++v )
5108 	   {
5109 	      int flexenergy;
5110 	      int minend;
5111 	      int ubenergy;
5112 	      int ubcand;
5113 	      int est;
5114 	      int i;
5115 	
5116 	      est = ests[v];
5117 	
5118 	      /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5119 	       * infinity capacity is available; hence we skip that
5120 	       */
5121 	      if( est < hmin )
5122 	         continue;
5123 	
5124 	      /* if the earliest start time is larger or equal then hmax we have to stop */
5125 	      if( est >= hmax )
5126 	         break;
5127 	
5128 	      /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5129 	       * induced by start was just analyzed
5130 	       */
5131 	      if( est == begin )
5132 	         continue;
5133 	
5134 	      assert(est > begin);
5135 	
5136 	      SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5137 	
5138 	      begin = est;
5139 	      coreEnergyAfterStart = coreEnergyAfterEst[v];
5140 	
5141 	      flexenergy = 0;
5142 	      minavailable = maxavailable;
5143 	      minend = hmin;
5144 	      ubcand = -1;
5145 	      ubenergy = 0;
5146 	
5147 	      /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5148 	       * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5149 	       */
5150 	      for( i = nlcts; i < nvars; ++i )
5151 	      {
5152 	         SCIP_VAR* var;
5153 	         SCIP_Longint freeenergy;
5154 	         int duration;
5155 	         int demand;
5156 	         int idx;
5157 	         int lct;
5158 	         int ect;
5159 	
5160 	         idx = perm[i];
5161 	         assert(idx >= 0);
5162 	         assert(idx < nvars);
5163 	         assert(!(*cutoff));
5164 	
5165 	         /* the earliest start time of the job */
5166 	         lct = lcts[i];
5167 	
5168 	         /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5169 	          * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5170 	          */
5171 	         if( lct <= begin )
5172 	         {
5173 	            nlcts++;
5174 	            continue;
5175 	         }
5176 	
5177 	         /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5178 	          * start with current beginning time
5179 	          */
5180 	         if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5181 	            break;
5182 	
5183 	         var = vars[idx];
5184 	         assert(var != NULL);
5185 	
5186 	         duration = durations[idx];
5187 	         assert(duration > 0);
5188 	
5189 	         demand = demands[idx];
5190 	         assert(demand > 0);
5191 	
5192 	         est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5193 	
5194 	         /* the earliest completion time of the flexible part of the job */
5195 	         ect = ects[idx];
5196 	
5197 	         /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5198 	          * investigation; hence the overload check will do the the job
5199 	          */
5200 	         assert(lct >= minend);
5201 	         if( minavailable < maxavailable && lct > minend )
5202 	         {
5203 	            assert(!(*cutoff));
5204 	
5205 	            /* try to tighten the upper bound */
5206 	            SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5207 	                  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5208 	                  initialized, explanation, cutoff) );
5209 	
5210 	            if( *cutoff )
5211 	               return SCIP_OKAY;
5212 	         }
5213 	
5214 	         SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5215 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5216 	
5217 	         end = lct;
5218 	         assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5219 	
5220 	         /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5221 	          * free energy
5222 	          */
5223 	         if( end > hmax )
5224 	            break;
5225 	
5226 	         /* compute the contribution to the flexible energy */
5227 	         if( est >= begin )
5228 	         {
5229 	            /* if the jobs has to finish before the end, all the energy has to be scheduled */
5230 	            assert(ect <= end);
5231 	            assert(flexenergies[idx] >= 0);
5232 	            flexenergy += flexenergies[idx];
5233 	         }
5234 	         else
5235 	         {
5236 	            /* the job partly overlaps with the end */
5237 	            int candenergy;
5238 	            int energy;
5239 	
5240 	            /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5241 	             * w.r.t. latest start time
5242 	             *
5243 	             * @note we need to be aware of the effective horizon
5244 	             */
5245 	            energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5246 	            assert(ect - begin < duration);
5247 	            assert(energy >= 0);
5248 	
5249 	            /* adjust the flexible energy of the time interval */
5250 	            flexenergy += energy;
5251 	
5252 	            /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5253 	            candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5254 	            assert(candenergy >= 0);
5255 	
5256 	            /* check if we found a better candidate */
5257 	            if( candenergy > ubenergy )
5258 	            {
5259 	               ubenergy = candenergy;
5260 	               ubcand = idx;
5261 	            }
5262 	         }
5263 	
5264 	         SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5265 	         assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5266 	
5267 	         /* compute the energy which is not used yet */
5268 	         freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5269 	
5270 	         /* check overload */
5271 	         if( freeenergy < 0 )
5272 	         {
5273 	            SCIPdebugMsg(scip, "analyze overload  within time window [%d,%d) capacity %d\n", begin, end, capacity);
5274 	
5275 	            /* initialize conflict analysis if conflict analysis is applicable */
5276 	            if( SCIPisConflictAnalysisApplicable(scip) )
5277 	            {
5278 	               /* analyze infeasibilty */
5279 	               SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
5280 	
5281 	               SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5282 	                     begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5283 	                     conshdlrdata->usebdwidening, explanation) );
5284 	
5285 	               (*initialized) = TRUE;
5286 	            }
5287 	
5288 	            (*cutoff) = TRUE;
5289 	
5290 	            /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5291 	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5292 	
5293 	            return SCIP_OKAY;
5294 	         }
5295 	
5296 	         /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5297 	         if( ubenergy > 0 && freeenergy < ubenergy )
5298 	         {
5299 	            SCIP_Longint energy;
5300 	            int newub;
5301 	            int lst;
5302 	
5303 	            duration = durations[ubcand];
5304 	            assert(duration > 0);
5305 	
5306 	            ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5307 	            lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5308 	
5309 	            /* remove the energy of our job from the ... */
5310 	            energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5311 	
5312 	            newub = begin - duration + (int)(energy / demands[ubcand]);
5313 	
5314 	            if( newub < ect - duration )
5315 	            {
5316 	               /* initialize conflict analysis if conflict analysis is applicable */
5317 	               if( SCIPisConflictAnalysisApplicable(scip) )
5318 	               {
5319 	                  SCIP_Real relaxedbd;
5320 	                  /* analyze infeasibilty */
5321 	                  SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
5322 	
5323 	                  relaxedbd = ect - duration - 1.0;
5324 	
5325 	                  /* added to lower bound (which was undercut be new upper bound) of the variable */
5326 	                  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5327 	
5328 	                  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5329 	                        begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5330 	                        conshdlrdata->usebdwidening, explanation) );
5331 	
5332 	                  (*initialized) = TRUE;
5333 	               }
5334 	
5335 	               (*cutoff) = TRUE;
5336 	               return SCIP_OKAY;
5337 	            }
5338 	            else if( newub < newubs[ubcand] )
5339 	            {
5340 	               INFERINFO inferinfo;
5341 	
5342 	               /* construct inference information */
5343 	               inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5344 	
5345 	               /* buffer upper bound change */
5346 	               ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5347 	               newubs[ubcand] = newub;
5348 	            }
5349 	         }
5350 	
5351 	         /* check if the current interval has a smaller free energy */
5352 	         if( minavailable > freeenergy )
5353 	         {
5354 	            minavailable = freeenergy;
5355 	            minend = end;
5356 	         }
5357 	         assert(minavailable >= 0);
5358 	      }
5359 	   }
5360 	
5361 	   return SCIP_OKAY;
5362 	}
5363 	
5364 	/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5365 	 *  edge-finding
5366 	 *
5367 	 *  @note The algorithm is based on the following two papers:
5368 	 *        - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5369 	 *          Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5370 	 *          Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5371 	 *        - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5372 	 *          Cumulative Resource Constraint (submitted to CPAIOR 2013)
5373 	 */
5374 	static
5375 	SCIP_RETCODE propagateTTEF(
5376 	   SCIP*                 scip,               /**< SCIP data structure */
5377 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
5378 	   SCIP_PROFILE*         profile,            /**< current core profile */
5379 	   int                   nvars,              /**< number of start time variables (activities) */
5380 	   SCIP_VAR**            vars,               /**< array of start time variables */
5381 	   int*                  durations,          /**< array of durations */
5382 	   int*                  demands,            /**< array of demands */
5383 	   int                   capacity,           /**< cumulative capacity */
5384 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
5385 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
5386 	   SCIP_CONS*            cons,               /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5387 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
5388 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
5389 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5390 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
5391 	   )
5392 	{
5393 	   int* coreEnergyAfterEst;
5394 	   int* coreEnergyAfterLct;
5395 	   int* flexenergies;
5396 	   int* permests;
5397 	   int* permlcts;
5398 	   int* lcts;
5399 	   int* ests;
5400 	   int* ects;
5401 	   int* lsts;
5402 	
5403 	   int* newlbs;
5404 	   int* newubs;
5405 	   int* lbinferinfos;
5406 	   int* ubinferinfos;
5407 	
5408 	   int v;
5409 	
5410 	   /* check if a cutoff was already detected */
5411 	   if( (*cutoff) )
5412 	      return SCIP_OKAY;
5413 	
5414 	   /* check if at least the basic overload checking should be perfomed */
5415 	   if( !conshdlrdata->ttefcheck )
5416 	      return SCIP_OKAY;
5417 	
5418 	   SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5419 	
5420 	   SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5421 	   SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5422 	   SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5423 	   SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5424 	   SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5425 	   SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5426 	   SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5427 	   SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5428 	   SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5429 	
5430 	   SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5431 	   SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5432 	   SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5433 	   SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5434 	
5435 	   /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5436 	   for( v = 0; v < nvars; ++v )
5437 	   {
5438 	      newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5439 	      newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5440 	      lbinferinfos[v] = 0;
5441 	      ubinferinfos[v] = 0;
5442 	   }
5443 	
5444 	   /* collect earliest start times, latest completion time, and free energy contributions */
5445 	   collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5446 	
5447 	   /* sort the earliest start times and latest completion in non-decreasing order */
5448 	   SCIPsortIntInt(ests, permests, nvars);
5449 	   SCIPsortIntInt(lcts, permlcts, nvars);
5450 	
5451 	   /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5452 	    * points
5453 	    */
5454 	   computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5455 	
5456 	   /* propagate the upper bounds and "opportunistically" the lower bounds */
5457 	   SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5458 	         newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5459 	         permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5460 	
5461 	   /* propagate the lower bounds and "opportunistically" the upper bounds */
5462 	   SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5463 	         newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5464 	         permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5465 	
5466 	   /* apply the buffer bound changes */
5467 	   for( v = 0; v < nvars && !(*cutoff); ++v )
5468 	   {
5469 	      SCIP_Bool infeasible;
5470 	      SCIP_Bool tightened;
5471 	
5472 	      if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5473 	      {
5474 	         SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5475 	               TRUE, &infeasible, &tightened) );
5476 	      }
5477 	      else
5478 	      {
5479 	         SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5480 	      }
5481 	
5482 	      /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5483 	      assert(!infeasible);
5484 	
5485 	      if( tightened )
5486 	      {
5487 	         (*nchgbds)++;
5488 	
5489 	         /* for the statistic we count the number of times a cutoff was detected due the time-time */
5490 	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nlbTTEF++ );
5491 	      }
5492 	
5493 	      if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5494 	      {
5495 	         SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5496 	               TRUE, &infeasible, &tightened) );
5497 	      }
5498 	      else
5499 	      {
5500 	         SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5501 	      }
5502 	
5503 	      /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5504 	       * bound update can be infeasible
5505 	       */
5506 	      if( infeasible )
5507 	      {
5508 	         /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5509 	          * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5510 	          * be analyzed in the case when begin and end exceed the 15 bit limit
5511 	          */
5512 	         if( SCIPisConflictAnalysisApplicable(scip) && inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5513 	         {
5514 	            INFERINFO inferinfo;
5515 	            SCIP_VAR* var;
5516 	            int begin;
5517 	            int end;
5518 	
5519 	            var = vars[v];
5520 	            assert(var != NULL);
5521 	
5522 	            /* initialize conflict analysis */
5523 	            SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
5524 	
5525 	            /* convert int to inference information */
5526 	            inferinfo = intToInferInfo(ubinferinfos[v]);
5527 	
5528 	            /* collect time window from inference information */
5529 	            begin = inferInfoGetData1(inferinfo);
5530 	            end = inferInfoGetData2(inferinfo);
5531 	            assert(begin < end);
5532 	
5533 	            /* added to lower bound (which was undercut be new upper bound) of the variable */
5534 	            SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5535 	
5536 	            /* analysis the upper bound change */
5537 	            SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5538 	                  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5539 	                  conshdlrdata->usebdwidening, explanation) );
5540 	
5541 	            (*initialized) = TRUE;
5542 	         }
5543 	
5544 	         /* for the statistic we count the number of times a cutoff was detected due the time-time */
5545 	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5546 	
5547 	         (*cutoff) = TRUE;
5548 	         break;
5549 	      }
5550 	
5551 	      if( tightened )
5552 	      {
5553 	         (*nchgbds)++;
5554 	
5555 	         /* for the statistic we count the number of times a cutoff was detected due the time-time */
5556 	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nubTTEF++ );
5557 	      }
5558 	   }
5559 	
5560 	   SCIPfreeBufferArray(scip, &ubinferinfos);
5561 	   SCIPfreeBufferArray(scip, &lbinferinfos);
5562 	   SCIPfreeBufferArray(scip, &newubs);
5563 	   SCIPfreeBufferArray(scip, &newlbs);
5564 	
5565 	   /* free buffer arrays */
5566 	   SCIPfreeBufferArray(scip, &lsts);
5567 	   SCIPfreeBufferArray(scip, &ects);
5568 	   SCIPfreeBufferArray(scip, &ests);
5569 	   SCIPfreeBufferArray(scip, &lcts);
5570 	   SCIPfreeBufferArray(scip, &permests);
5571 	   SCIPfreeBufferArray(scip, &permlcts);
5572 	   SCIPfreeBufferArray(scip, &flexenergies);
5573 	   SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5574 	   SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5575 	
5576 	   return SCIP_OKAY;
5577 	}
5578 	
5579 	/** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5580 	 *  anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5581 	 *  time table propagator
5582 	 */
5583 	static
5584 	SCIP_RETCODE propagateTimetable(
5585 	   SCIP*                 scip,               /**< SCIP data structure */
5586 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
5587 	   SCIP_PROFILE*         profile,            /**< core profile */
5588 	   int                   nvars,              /**< number of start time variables (activities) */
5589 	   SCIP_VAR**            vars,               /**< array of start time variables */
5590 	   int*                  durations,          /**< array of durations */
5591 	   int*                  demands,            /**< array of demands */
5592 	   int                   capacity,           /**< cumulative capacity */
5593 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
5594 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
5595 	   SCIP_CONS*            cons,               /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5596 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
5597 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
5598 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5599 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
5600 	   )
5601 	{
5602 	   SCIP_Bool infeasible;
5603 	   int v;
5604 	
5605 	   assert(scip != NULL);
5606 	   assert(nvars > 0);
5607 	   assert(cons != NULL);
5608 	   assert(cutoff !=  NULL);
5609 	
5610 	   /* check if already a cutoff was detected */
5611 	   if( (*cutoff) )
5612 	      return SCIP_OKAY;
5613 	
5614 	   /* check if the time tabling should infer bounds */
5615 	   if( !conshdlrdata->ttinfer )
5616 	      return SCIP_OKAY;
5617 	
5618 	   assert(*initialized ==  FALSE);
5619 	
5620 	   SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5621 	      SCIPconsGetName(cons), hmin, hmax, capacity);
5622 	
5623 	   infeasible = FALSE;
5624 	
5625 	   /* if core profile is empty; nothing to do */
5626 	   if( SCIPprofileGetNTimepoints(profile) <= 1 )
5627 	      return SCIP_OKAY;
5628 	
5629 	   /* start checking each job whether the bounds can be improved */
5630 	   for( v = 0; v < nvars; ++v )
5631 	   {
5632 	      SCIP_VAR* var;
5633 	      int demand;
5634 	      int duration;
5635 	      int begin;
5636 	      int end;
5637 	      int est;
5638 	      int lst;
5639 	
5640 	      var = vars[v];
5641 	      assert(var != NULL);
5642 	
5643 	      duration = durations[v];
5644 	      assert(duration > 0);
5645 	
5646 	      /* collect earliest and latest start time */
5647 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5648 	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5649 	
5650 	      /* check if the start time variables is already fixed; in that case we can ignore the job */
5651 	      if( est == lst )
5652 	         continue;
5653 	
5654 	      /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5655 	      if( lst + duration <= hmin || est >= hmax )
5656 	         continue;
5657 	
5658 	      /* compute core interval w.r.t. effective time horizon */
5659 	      begin = MAX(hmin, lst);
5660 	      end = MIN(hmax, est + duration);
5661 	
5662 	      demand = demands[v];
5663 	      assert(demand > 0);
5664 	
5665 	      /* if the job has a core, remove it first */
5666 	      if( begin < end  )
5667 	      {
5668 	         SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5669 	            SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5670 	
5671 	         SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5672 	      }
5673 	
5674 	      /* first try to update the earliest start time */
5675 	      SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5676 	            profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5677 	
5678 	      if( *cutoff )
5679 	         break;
5680 	
5681 	      /* second try to update the latest start time */
5682 	      SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5683 	            profile, v, nchgbds) );
5684 	
5685 	      if( *cutoff )
5686 	         break;
5687 	
5688 	      /* collect the potentially updated earliest and latest start time */
5689 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5690 	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5691 	
5692 	      /* compute core interval w.r.t. effective time horizon */
5693 	      begin = MAX(hmin, lst);
5694 	      end = MIN(hmax, est + duration);
5695 	
5696 	      /* after updating the bound we might have a new core */
5697 	      if( begin < end )
5698 	      {
5699 	         int pos;
5700 	
5701 	         SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5702 	            SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5703 	
5704 	         SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5705 	
5706 	         if( infeasible )
5707 	         {
5708 	            /* use conflict analysis to analysis the core insertion which was infeasible */
5709 	            SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5710 	                  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5711 	
5712 	            if( explanation != NULL )
5713 	               explanation[v] = TRUE;
5714 	
5715 	            (*cutoff) = TRUE;
5716 	
5717 	            /* for the statistic we count the number of times a cutoff was detected due the time-time */
5718 	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5719 	
5720 	            break;
5721 	         }
5722 	      }
5723 	   }
5724 	
5725 	   return SCIP_OKAY;
5726 	}
5727 	
5728 	
5729 	/** node data structure for the binary tree used for edgefinding (with overload checking) */
5730 	struct SCIP_NodeData
5731 	{
5732 	   SCIP_VAR*             var;                /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5733 	   SCIP_Real             key;                /**< key which is to insert the corresponding search node */
5734 	   int                   est;                /**< earliest start time if the node data belongs to a leaf */
5735 	   int                   lct;                /**< latest completion time if the node data belongs to a leaf */
5736 	   int                   demand;             /**< demand of the job if the node data belongs to a leaf */
5737 	   int                   duration;           /**< duration of the job if the node data belongs to a leaf */
5738 	   int                   leftadjust;         /**< left adjustments of the duration w.r.t. hmin */
5739 	   int                   rightadjust;        /**< right adjustments of the duration w.r.t. hmax */
5740 	   SCIP_Longint          enveloptheta;       /**< the maximal energy of a subset of jobs part of the theta set */
5741 	   int                   energytheta;        /**< energy of the subset of the jobs which are part of theta set */
5742 	   int                   energylambda;
5743 	   SCIP_Longint          enveloplambda;
5744 	   int                   idx;                /**< index of the start time variable in the (global) variable array */
5745 	   SCIP_Bool             intheta;            /**< belongs the node to the theta set (otherwise to the lambda set) */
5746 	};
5747 	typedef struct SCIP_NodeData SCIP_NODEDATA;
5748 	
5749 	
5750 	/** update node data structure starting from the given node along the path to the root node */
5751 	static
5752 	void updateEnvelope(
5753 	   SCIP*                 scip,               /**< SCIP data structure */
5754 	   SCIP_BTNODE*          node                /**< search node which inserted */
5755 	   )
5756 	{
5757 	   SCIP_BTNODE* left;
5758 	   SCIP_BTNODE* right;
5759 	   SCIP_NODEDATA* nodedata;
5760 	   SCIP_NODEDATA* leftdata;
5761 	   SCIP_NODEDATA* rightdata;
5762 	
5763 	   SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5764 	
5765 	   if( SCIPbtnodeIsLeaf(node) )
5766 	      node = SCIPbtnodeGetParent(node);
5767 	
5768 	   while( node != NULL )
5769 	   {
5770 	      /* get node data */
5771 	      nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5772 	      assert(nodedata != NULL);
5773 	
5774 	      /* collect node data from left node */
5775 	      left = SCIPbtnodeGetLeftchild(node);
5776 	      assert(left != NULL);
5777 	      leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5778 	      assert(leftdata != NULL);
5779 	
5780 	      /* collect node data from right node */
5781 	      right = SCIPbtnodeGetRightchild(node);
5782 	      assert(right != NULL);
5783 	      rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5784 	      assert(rightdata != NULL);
5785 	
5786 	      /* update envelop and energy */
5787 	      if( leftdata->enveloptheta >= 0 )
5788 	      {
5789 	         assert(rightdata->energytheta != -1);
5790 	         nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5791 	      }
5792 	      else
5793 	         nodedata->enveloptheta = rightdata->enveloptheta;
5794 	
5795 	      assert(leftdata->energytheta != -1);
5796 	      assert(rightdata->energytheta != -1);
5797 	      nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5798 	
5799 	      if( leftdata->enveloplambda >= 0 )
5800 	      {
5801 	         assert(rightdata->energytheta != -1);
5802 	         nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5803 	      }
5804 	      else
5805 	         nodedata->enveloplambda = rightdata->enveloplambda;
5806 	
5807 	      if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5808 	         nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5809 	
5810 	      SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5811 	
5812 	      if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5813 	      {
5814 	         assert(rightdata->energytheta != -1);
5815 	         assert(leftdata->energytheta != -1);
5816 	         nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5817 	      }
5818 	      else if( rightdata->energylambda >= 0 )
5819 	      {
5820 	         assert(leftdata->energytheta != -1);
5821 	         nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5822 	      }
5823 	      else if( leftdata->energylambda >= 0 )
5824 	      {
5825 	         assert(rightdata->energytheta != -1);
5826 	         nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5827 	      }
5828 	      else
5829 	         nodedata->energylambda = -1;
5830 	
5831 	      /* go to parent */
5832 	      node = SCIPbtnodeGetParent(node);
5833 	   }
5834 	
5835 	   SCIPdebugMsg(scip, "updating done\n");
5836 	}
5837 	
5838 	/** updates the key of the first parent on the trace which comes from left */
5839 	static
5840 	void updateKeyOnTrace(
5841 	   SCIP_BTNODE*          node,               /**< node to start the trace */
5842 	   SCIP_Real             key                 /**< update search key */
5843 	   )
5844 	{
5845 	   assert(node != NULL);
5846 	
5847 	   while( !SCIPbtnodeIsRoot(node) )
5848 	   {
5849 	      SCIP_BTNODE* parent;
5850 	
5851 	      parent = SCIPbtnodeGetParent(node);
5852 	      assert(parent != NULL);
5853 	
5854 	      if( SCIPbtnodeIsLeftchild(node) )
5855 	      {
5856 	         SCIP_NODEDATA* nodedata;
5857 	
5858 	         nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5859 	         assert(nodedata != NULL);
5860 	
5861 	         nodedata->key = key;
5862 	         return;
5863 	      }
5864 	
5865 	      node = parent;
5866 	   }
5867 	}
5868 	
5869 	
5870 	/** deletes the given node and updates all envelops */
5871 	static
5872 	SCIP_RETCODE deleteLambdaLeaf(
5873 	   SCIP*                 scip,               /**< SCIP data structure */
5874 	   SCIP_BT*              tree,               /**< binary tree */
5875 	   SCIP_BTNODE*          node                /**< node to be deleted */
5876 	   )
5877 	{
5878 	   SCIP_BTNODE* parent;
5879 	   SCIP_BTNODE* grandparent;
5880 	   SCIP_BTNODE* sibling;
5881 	
5882 	   assert(scip != NULL);
5883 	   assert(tree != NULL);
5884 	   assert(node != NULL);
5885 	
5886 	   assert(SCIPbtnodeIsLeaf(node));
5887 	   assert(!SCIPbtnodeIsRoot(node));
5888 	
5889 	   SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5890 	
5891 	   parent = SCIPbtnodeGetParent(node);
5892 	   assert(parent != NULL);
5893 	   if( SCIPbtnodeIsLeftchild(node) )
5894 	   {
5895 	      sibling = SCIPbtnodeGetRightchild(parent);
5896 	      SCIPbtnodeSetRightchild(parent, NULL);
5897 	   }
5898 	   else
5899 	   {
5900 	      sibling = SCIPbtnodeGetLeftchild(parent);
5901 	      SCIPbtnodeSetLeftchild(parent, NULL);
5902 	   }
5903 	   assert(sibling != NULL);
5904 	
5905 	   grandparent = SCIPbtnodeGetParent(parent);
5906 	
5907 	   if( grandparent != NULL )
5908 	   {
5909 	      /* reset parent of sibling */
5910 	      SCIPbtnodeSetParent(sibling, grandparent);
5911 	
5912 	      /* reset child of grandparent to sibling */
5913 	      if( SCIPbtnodeIsLeftchild(parent) )
5914 	      {
5915 	         SCIPbtnodeSetLeftchild(grandparent, sibling);
5916 	      }
5917 	      else
5918 	      {
5919 	         SCIP_NODEDATA* nodedata;
5920 	
5921 	         assert(SCIPbtnodeIsRightchild(parent));
5922 	         SCIPbtnodeSetRightchild(grandparent, sibling);
5923 	
5924 	         nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5925 	
5926 	         updateKeyOnTrace(grandparent, nodedata->key);
5927 	      }
5928 	
5929 	      updateEnvelope(scip, grandparent);
5930 	   }
5931 	   else
5932 	   {
5933 	      SCIPbtnodeSetParent(sibling, NULL);
5934 	
5935 	      SCIPbtSetRoot(tree, sibling);
5936 	   }
5937 	
5938 	   SCIPbtnodeFree(tree, &parent);
5939 	
5940 	   return SCIP_OKAY;
5941 	}
5942 	
5943 	/** moves a node form the theta set into the lambda set and updates the envelops */
5944 	static
5945 	SCIP_RETCODE moveNodeToLambda(
5946 	   SCIP*                 scip,               /**< SCIP data structure */
5947 	   SCIP_BT*              tree,               /**< binary tree */
5948 	   SCIP_BTNODE*          node                /**< node to move into the lambda set */
5949 	   )
5950 	{
5951 	   SCIP_NODEDATA* nodedata;
5952 	
5953 	   assert(scip != NULL);
5954 	   assert(tree != NULL);
5955 	   assert(node != NULL);
5956 	
5957 	   nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5958 	   assert(nodedata != NULL);
5959 	   assert(nodedata->intheta);
5960 	
5961 	   /* move the contributions form the theta set into the lambda set */
5962 	   assert(nodedata->enveloptheta != -1);
5963 	   assert(nodedata->energytheta != -1);
5964 	   assert(nodedata->enveloplambda == -1);
5965 	   assert(nodedata->energylambda == -1);
5966 	   nodedata->enveloplambda = nodedata->enveloptheta;
5967 	   nodedata->energylambda = nodedata->energytheta;
5968 	
5969 	   nodedata->enveloptheta = -1;
5970 	   nodedata->energytheta = 0;
5971 	   nodedata->intheta = FALSE;
5972 	
5973 	   /* update the energy and envelop values on trace */
5974 	   updateEnvelope(scip, node);
5975 	
5976 	   return SCIP_OKAY;
5977 	}
5978 	
5979 	/** inserts a node into the theta set and update the envelops */
5980 	static
5981 	SCIP_RETCODE insertThetanode(
5982 	   SCIP*                 scip,               /**< SCIP data structure */
5983 	   SCIP_BT*              tree,               /**< binary tree */
5984 	   SCIP_BTNODE*          node,               /**< node to insert */
5985 	   SCIP_NODEDATA*        nodedatas,          /**< array of node data */
5986 	   int*                  nodedataidx,        /**< array of indices for node data */
5987 	   int*                  nnodedatas          /**< pointer to number of node data */
5988 	   )
5989 	{
5990 	   /* if the tree is empty the node will be the root node */
5991 	   if( SCIPbtIsEmpty(tree) )
5992 	   {
5993 	      SCIPbtSetRoot(tree, node);
5994 	   }
5995 	   else
5996 	   {
5997 	      SCIP_NODEDATA* newnodedata;
5998 	      SCIP_NODEDATA* leafdata;
5999 	      SCIP_NODEDATA* nodedata;
6000 	      SCIP_BTNODE* leaf;
6001 	      SCIP_BTNODE* newnode;
6002 	      SCIP_BTNODE* parent;
6003 	
6004 	      leaf = SCIPbtGetRoot(tree);
6005 	      assert(leaf != NULL);
6006 	
6007 	      leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6008 	      assert(leafdata != NULL);
6009 	
6010 	      nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6011 	      assert(nodedata != NULL);
6012 	      assert(nodedata->intheta);
6013 	
6014 	      /* find the position to insert the node */
6015 	      while( !SCIPbtnodeIsLeaf(leaf) )
6016 	      {
6017 	         if( nodedata->key < leafdata->key )
6018 	            leaf = SCIPbtnodeGetLeftchild(leaf);
6019 	         else
6020 	            leaf = SCIPbtnodeGetRightchild(leaf);
6021 	
6022 	         leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6023 	         assert(leafdata != NULL);
6024 	      }
6025 	
6026 	      assert(leaf != NULL);
6027 	      assert(leaf != node);
6028 	
6029 	      /* store node data to be able to delete them latter */
6030 	      newnodedata = &nodedatas[*nnodedatas];
6031 	      nodedataidx[*nnodedatas] = *nnodedatas;
6032 	      ++(*nnodedatas);
6033 	
6034 	      /* init node data */
6035 	      newnodedata->var = NULL;
6036 	      newnodedata->key = SCIP_INVALID;
6037 	      newnodedata->est = INT_MIN;
6038 	      newnodedata->lct = INT_MAX;
6039 	      newnodedata->duration = 0;
6040 	      newnodedata->demand = 0;
6041 	      newnodedata->enveloptheta = -1;
6042 	      newnodedata->energytheta = 0;
6043 	      newnodedata->enveloplambda = -1;
6044 	      newnodedata->energylambda = -1;
6045 	      newnodedata->idx = -1;
6046 	      newnodedata->intheta = TRUE;
6047 	
6048 	      /* create a new node */
6049 	      SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6050 	      assert(newnode != NULL);
6051 	
6052 	      parent = SCIPbtnodeGetParent(leaf);
6053 	
6054 	      if( parent != NULL )
6055 	      {
6056 	         SCIPbtnodeSetParent(newnode, parent);
6057 	
6058 	         /* check if the node is the left child */
6059 	         if( SCIPbtnodeGetLeftchild(parent) == leaf )
6060 	         {
6061 	            SCIPbtnodeSetLeftchild(parent, newnode);
6062 	         }
6063 	         else
6064 	         {
6065 	            SCIPbtnodeSetRightchild(parent, newnode);
6066 	         }
6067 	      }
6068 	      else
6069 	         SCIPbtSetRoot(tree, newnode);
6070 	
6071 	      if( nodedata->key < leafdata->key )
6072 	      {
6073 	         /* node is on the left */
6074 	         SCIPbtnodeSetLeftchild(newnode, node);
6075 	         SCIPbtnodeSetRightchild(newnode, leaf);
6076 	         newnodedata->key = nodedata->key;
6077 	      }
6078 	      else
6079 	      {
6080 	         /* leaf is on the left */
6081 	         SCIPbtnodeSetLeftchild(newnode, leaf);
6082 	         SCIPbtnodeSetRightchild(newnode, node);
6083 	         newnodedata->key = leafdata->key;
6084 	      }
6085 	
6086 	      SCIPbtnodeSetParent(leaf, newnode);
6087 	      SCIPbtnodeSetParent(node, newnode);
6088 	   }
6089 	
6090 	   /* update envelop */
6091 	   updateEnvelope(scip, node);
6092 	
6093 	   return SCIP_OKAY;
6094 	}
6095 	
6096 	/** returns the leaf responsible for the lambda energy */
6097 	static
6098 	SCIP_BTNODE* findResponsibleLambdaLeafTraceEnergy(
6099 	   SCIP_BTNODE*          node                /**< node which defines the subtree beases on the lambda energy */
6100 	   )
6101 	{
6102 	   SCIP_BTNODE* left;
6103 	   SCIP_BTNODE* right;
6104 	   SCIP_NODEDATA* nodedata;
6105 	   SCIP_NODEDATA* leftdata;
6106 	   SCIP_NODEDATA* rightdata;
6107 	
6108 	   assert(node != NULL);
6109 	
6110 	   nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6111 	   assert(nodedata != NULL);
6112 	
6113 	   /* check if the node is the (responsible) leaf */
6114 	   if( SCIPbtnodeIsLeaf(node) )
6115 	   {
6116 	      assert(!nodedata->intheta);
6117 	      return node;
6118 	   }
6119 	
6120 	   left = SCIPbtnodeGetLeftchild(node);
6121 	   assert(left != NULL);
6122 	
6123 	   leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6124 	   assert(leftdata != NULL);
6125 	
6126 	   right = SCIPbtnodeGetRightchild(node);
6127 	   assert(right != NULL);
6128 	
6129 	   rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6130 	   assert(rightdata != NULL);
6131 	
6132 	   assert(nodedata->energylambda != -1);
6133 	   assert(rightdata->energytheta != -1);
6134 	
6135 	   if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6136 	      return findResponsibleLambdaLeafTraceEnergy(left);
6137 	
6138 	   assert(leftdata->energytheta != -1);
6139 	   assert(rightdata->energylambda != -1);
6140 	   assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6141 	
6142 	   return findResponsibleLambdaLeafTraceEnergy(right);
6143 	}
6144 	
6145 	/** returns the leaf responsible for the lambda envelop */
6146 	static
6147 	SCIP_BTNODE* findResponsibleLambdaLeafTraceEnvelop(
6148 	   SCIP_BTNODE*          node                /**< node which defines the subtree beases on the lambda envelop */
6149 	   )
6150 	{
6151 	   SCIP_BTNODE* left;
6152 	   SCIP_BTNODE* right;
6153 	   SCIP_NODEDATA* nodedata;
6154 	   SCIP_NODEDATA* leftdata;
6155 	   SCIP_NODEDATA* rightdata;
6156 	
6157 	   assert(node != NULL);
6158 	
6159 	   nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6160 	   assert(nodedata != NULL);
6161 	
6162 	   /* check if the node is the (responsible) leaf */
6163 	   if( SCIPbtnodeIsLeaf(node) )
6164 	   {
6165 	      assert(!nodedata->intheta);
6166 	      return node;
6167 	   }
6168 	
6169 	   left = SCIPbtnodeGetLeftchild(node);
6170 	   assert(left != NULL);
6171 	
6172 	   leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6173 	   assert(leftdata != NULL);
6174 	
6175 	   right = SCIPbtnodeGetRightchild(node);
6176 	   assert(right != NULL);
6177 	
6178 	   rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6179 	   assert(rightdata != NULL);
6180 	
6181 	   assert(nodedata->enveloplambda != -1);
6182 	   assert(rightdata->energytheta != -1);
6183 	
6184 	   /* check if the left or right child is the one defining the envelop for the lambda set */
6185 	   if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6186 	      return findResponsibleLambdaLeafTraceEnvelop(left);
6187 	   else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6188 	      && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6189 	      return findResponsibleLambdaLeafTraceEnergy(right);
6190 	
6191 	   assert(rightdata->enveloplambda != -1);
6192 	   assert(nodedata->enveloplambda == rightdata->enveloplambda);
6193 	
6194 	   return findResponsibleLambdaLeafTraceEnvelop(right);
6195 	}
6196 	
6197 	
6198 	/** reports all elements from set theta to generate a conflicting set */
6199 	static
6200 	void collectThetaSubtree(
6201 	   SCIP_BTNODE*          node,               /**< node within a theta subtree */
6202 	   SCIP_BTNODE**         omegaset,           /**< array to store the collected jobs */
6203 	   int*                  nelements,          /**< pointer to store the number of elements in omegaset */
6204 	   int*                  est,                /**< pointer to store the earliest start time of the omega set */
6205 	   int*                  lct,                /**< pointer to store the latest start time of the omega set */
6206 	   int*                  energy              /**< pointer to store the energy of the omega set */
6207 	   )
6208 	{
6209 	   SCIP_NODEDATA* nodedata;
6210 	
6211 	   nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6212 	   assert(nodedata != NULL);
6213 	
6214 	   if( !SCIPbtnodeIsLeaf(node) )
6215 	   {
6216 	      collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6217 	      collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6218 	   }
6219 	   else if( nodedata->intheta )
6220 	   {
6221 	      assert(nodedata->var != NULL);
6222 	      SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6223 	
6224 	      omegaset[*nelements] = node;
6225 	      (*est) = MIN(*est, nodedata->est);
6226 	      (*lct) = MAX(*lct, nodedata->lct);
6227 	      (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6228 	      (*nelements)++;
6229 	   }
6230 	}
6231 	
6232 	
6233 	/** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6234 	static
6235 	void traceThetaEnvelop(
6236 	   SCIP_BTNODE*          node,               /**< node whose theta envelop needs to be backtracked */
6237 	   SCIP_BTNODE**         omegaset,           /**< array to store the collected jobs */
6238 	   int*                  nelements,          /**< pointer to store the number of elements in omegaset */
6239 	   int*                  est,                /**< pointer to store the earliest start time of the omega set */
6240 	   int*                  lct,                /**< pointer to store the latest start time of the omega set */
6241 	   int*                  energy              /**< pointer to store the energy of the omega set */
6242 	   )
6243 	{
6244 	   assert(node != NULL);
6245 	
6246 	   if( SCIPbtnodeIsLeaf(node) )
6247 	   {
6248 	      collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6249 	   }
6250 	   else
6251 	   {
6252 	      SCIP_BTNODE* left;
6253 	      SCIP_BTNODE* right;
6254 	      SCIP_NODEDATA* nodedata;
6255 	      SCIP_NODEDATA* leftdata;
6256 	      SCIP_NODEDATA* rightdata;
6257 	
6258 	      nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6259 	      assert(nodedata != NULL);
6260 	
6261 	      left = SCIPbtnodeGetLeftchild(node);
6262 	      assert(left != NULL);
6263 	
6264 	      leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6265 	      assert(leftdata != NULL);
6266 	
6267 	      right = SCIPbtnodeGetRightchild(node);
6268 	      assert(right != NULL);
6269 	
6270 	      rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6271 	      assert(rightdata != NULL);
6272 	
6273 	      nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6274 	      assert(nodedata != NULL);
6275 	
6276 	      assert(nodedata->enveloptheta != -1);
6277 	      assert(rightdata->energytheta != -1);
6278 	
6279 	      if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6280 	      {
6281 	         traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6282 	         collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6283 	      }
6284 	      else
6285 	      {
6286 	         assert(rightdata->enveloptheta != -1);
6287 	         assert(nodedata->enveloptheta == rightdata->enveloptheta);
6288 	         traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6289 	      }
6290 	   }
6291 	}
6292 	
6293 	/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6294 	static
6295 	void traceLambdaEnergy(
6296 	   SCIP_BTNODE*          node,               /**< node whose lambda envelop needs to be backtracked */
6297 	   SCIP_BTNODE**         omegaset,           /**< array to store the collected jobs */
6298 	   int*                  nelements,          /**< pointer to store the number of elements in omega set */
6299 	   int*                  est,                /**< pointer to store the earliest start time of the omega set */
6300 	   int*                  lct,                /**< pointer to store the latest start time of the omega set */
6301 	   int*                  energy              /**< pointer to store the energy of the omega set */
6302 	   )
6303 	{
6304 	   SCIP_BTNODE* left;
6305 	   SCIP_BTNODE* right;
6306 	   SCIP_NODEDATA* nodedata;
6307 	   SCIP_NODEDATA* leftdata;
6308 	   SCIP_NODEDATA* rightdata;
6309 	
6310 	   assert(node != NULL);
6311 	
6312 	   nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6313 	   assert(nodedata != NULL);
6314 	
6315 	   /* check if the node is a leaf */
6316 	   if( SCIPbtnodeIsLeaf(node) )
6317 	      return;
6318 	
6319 	   left = SCIPbtnodeGetLeftchild(node);
6320 	   assert(left != NULL);
6321 	
6322 	   leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6323 	   assert(leftdata != NULL);
6324 	
6325 	   right = SCIPbtnodeGetRightchild(node);
6326 	   assert(right != NULL);
6327 	
6328 	   rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6329 	   assert(rightdata != NULL);
6330 	
6331 	   assert(nodedata->energylambda != -1);
6332 	   assert(rightdata->energytheta != -1);
6333 	
6334 	   if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6335 	   {
6336 	      traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6337 	      collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6338 	   }
6339 	   else
6340 	   {
6341 	      assert(leftdata->energytheta != -1);
6342 	      assert(rightdata->energylambda != -1);
6343 	      assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6344 	
6345 	      collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6346 	      traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6347 	   }
6348 	}
6349 	
6350 	/** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6351 	static
6352 	void traceLambdaEnvelop(
6353 	   SCIP_BTNODE*          node,               /**< node whose lambda envelop needs to be backtracked */
6354 	   SCIP_BTNODE**         omegaset,           /**< array to store the collected jobs */
6355 	   int*                  nelements,          /**< pointer to store the number of elements in omega set */
6356 	   int*                  est,                /**< pointer to store the earliest start time of the omega set */
6357 	   int*                  lct,                /**< pointer to store the latest start time of the omega set */
6358 	   int*                  energy              /**< pointer to store the energy of the omega set */
6359 	   )
6360 	{
6361 	   SCIP_BTNODE* left;
6362 	   SCIP_BTNODE* right;
6363 	   SCIP_NODEDATA* nodedata;
6364 	   SCIP_NODEDATA* leftdata;
6365 	   SCIP_NODEDATA* rightdata;
6366 	
6367 	   assert(node != NULL);
6368 	
6369 	   nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6370 	   assert(nodedata != NULL);
6371 	
6372 	   /* check if the node is a leaf */
6373 	   if( SCIPbtnodeIsLeaf(node) )
6374 	   {
6375 	      assert(!nodedata->intheta);
6376 	      return;
6377 	   }
6378 	
6379 	   left = SCIPbtnodeGetLeftchild(node);
6380 	   assert(left != NULL);
6381 	
6382 	   leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6383 	   assert(leftdata != NULL);
6384 	
6385 	   right = SCIPbtnodeGetRightchild(node);
6386 	   assert(right != NULL);
6387 	
6388 	   rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6389 	   assert(rightdata != NULL);
6390 	
6391 	   assert(nodedata->enveloplambda != -1);
6392 	   assert(rightdata->energytheta != -1);
6393 	
6394 	   if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6395 	   {
6396 	      traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6397 	      collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6398 	   }
6399 	   else
6400 	   {
6401 	      if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6402 	         && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6403 	      {
6404 	         traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6405 	         traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6406 	      }
6407 	      else
6408 	      {
6409 	         assert(rightdata->enveloplambda != -1);
6410 	         assert(nodedata->enveloplambda == rightdata->enveloplambda);
6411 	         traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6412 	      }
6413 	   }
6414 	}
6415 	
6416 	/** compute the energy contribution by job which corresponds to the given leaf */
6417 	static
6418 	int computeEnergyContribution(
6419 	   SCIP_BTNODE*          node                /**< leaf */
6420 	   )
6421 	{
6422 	   SCIP_NODEDATA* nodedata;
6423 	   int duration;
6424 	
6425 	   nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6426 	   assert(nodedata != NULL);
6427 	   assert(nodedata->var != NULL);
6428 	
6429 	   duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6430 	   assert(duration > 0);
6431 	
6432 	   SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6433 	      SCIPvarGetName(nodedata->var), SCIPvarGetLbLocal(nodedata->var), SCIPvarGetUbLocal(nodedata->var),
6434 	      SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6435 	
6436 	   /* return energy which is contributed by the start time variable */
6437 	   return nodedata->demand * duration;
6438 	}
6439 	
6440 	/** comparison method for two node data w.r.t. the earliest start time */
6441 	static
6442 	SCIP_DECL_SORTPTRCOMP(compNodeEst)
6443 	{
6444 	   int est1;
6445 	   int est2;
6446 	
6447 	   est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6448 	   est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6449 	
6450 	   return (est1 - est2);
6451 	}
6452 	
6453 	/** comparison method for two node data w.r.t. the latest completion time */
6454 	static
6455 	SCIP_DECL_SORTINDCOMP(compNodedataLct)
6456 	{
6457 	   SCIP_NODEDATA* nodedatas;
6458 	
6459 	   nodedatas = (SCIP_NODEDATA*) dataptr;
6460 	   return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6461 	}
6462 	
6463 	
6464 	/** an overload was detected; initialized conflict analysis, add an initial reason
6465 	 *
6466 	 *  @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6467 	 */
6468 	static
6469 	SCIP_RETCODE analyzeConflictOverload(
6470 	   SCIP*                 scip,               /**< SCIP data structure */
6471 	   SCIP_BTNODE**         leaves,             /**< responsible leaves for the overload */
6472 	   int                   capacity,           /**< cumulative capacity */
6473 	   int                   nleaves,            /**< number of responsible leaves */
6474 	   int                   est,                /**< earliest start time of the ...... */
6475 	   int                   lct,                /**< latest completly time of the .... */
6476 	   int                   reportedenergy,     /**< energy which already reported */
6477 	   SCIP_Bool             propest,            /**< should the earliest start times be propagated, otherwise the latest completion times */
6478 	   int                   shift,              /**< shift applied to all jobs before adding them to the tree */
6479 	   SCIP_Bool             usebdwidening,      /**< should bound widening be used during conflict analysis? */
6480 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
6481 	   SCIP_Bool*            explanation         /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6482 	   )
6483 	{
6484 	   SCIP_Longint energy;
6485 	   int j;
6486 	
6487 	   /* do nothing if conflict analysis is not applicable */
6488 	   if( !SCIPisConflictAnalysisApplicable(scip) )
6489 	      return SCIP_OKAY;
6490 	
6491 	   SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6492 	
6493 	   /* compute energy of initial time window */
6494 	   energy = ((SCIP_Longint) lct - est) * capacity;
6495 	
6496 	   /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6497 	   SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6498 	
6499 	   /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6500 	    * thereby, compute the time window of interest
6501 	    */
6502 	   for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6503 	   {
6504 	      SCIP_NODEDATA* nodedata;
6505 	
6506 	      nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6507 	      assert(nodedata != NULL);
6508 	
6509 	      reportedenergy += computeEnergyContribution(leaves[j]);
6510 	
6511 	      /* adjust energy if the earliest start time decrease */
6512 	      if( nodedata->est < est )
6513 	      {
6514 	         est = nodedata->est;
6515 	         energy = ((SCIP_Longint) lct - est) * capacity;
6516 	      }
6517 	   }
6518 	   assert(reportedenergy > energy);
6519 	
6520 	   SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6521 	
6522 	   /* initialize conflict analysis */
6523 	   SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
6524 	
6525 	   /* flip earliest start time and latest completion time */
6526 	   if( !propest )
6527 	   {
6528 	      SCIPswapInts(&est, &lct);
6529 	
6530 	      /* shift earliest start time and latest completion time */
6531 	      lct = shift - lct;
6532 	      est = shift - est;
6533 	   }
6534 	   else
6535 	   {
6536 	      /* shift earliest start time and latest completion time */
6537 	      lct = lct + shift;
6538 	      est = est + shift;
6539 	   }
6540 	
6541 	   nleaves = j;
6542 	
6543 	   /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6544 	    * overloaded
6545 	    */
6546 	   for( j = nleaves-1; j >= 0; --j )
6547 	   {
6548 	      SCIP_NODEDATA* nodedata;
6549 	
6550 	      nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6551 	      assert(nodedata != NULL);
6552 	      assert(nodedata->var != NULL);
6553 	
6554 	      /* check if bound widening should be used */
6555 	      if( usebdwidening )
6556 	      {
6557 	         SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6558 	         SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6559 	      }
6560 	      else
6561 	      {
6562 	         SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6563 	         SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6564 	      }
6565 	
6566 	      if( explanation != NULL )
6567 	         explanation[nodedata->idx] = TRUE;
6568 	   }
6569 	
6570 	   (*initialized) = TRUE;
6571 	
6572 	   return SCIP_OKAY;
6573 	}
6574 	
6575 	/** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6576 	 *  responsible interval bounds in *est_omega and *lct_omega
6577 	 */
6578 	static
6579 	int computeEstOmegaset(
6580 	   SCIP*                 scip,               /**< SCIP data structure */
6581 	   int                   duration,           /**< duration of the job to move */
6582 	   int                   demand,             /**< demand of the job to move */
6583 	   int                   capacity,           /**< cumulative capacity */
6584 	   int                   est,                /**< earliest start time of the omega set */
6585 	   int                   lct,                /**< latest start time of the omega set */
6586 	   int                   energy              /**< energy of the omega set */
6587 	   )
6588 	{
6589 	   int newest;
6590 	
6591 	   newest = 0;
6592 	
6593 	   assert(scip != NULL);
6594 	
6595 	   if( energy >  ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6596 	   {
6597 	      if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6598 	      {
6599 	         newest =  (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6600 	         newest += est;
6601 	      }
6602 	   }
6603 	
6604 	   return newest;
6605 	}
6606 	
6607 	/** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6608 	 *
6609 	 * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6610 	 *       Resources in O(kn log n)".  *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6611 	 */
6612 	static
6613 	SCIP_RETCODE inferboundsEdgeFinding(
6614 	   SCIP*                 scip,               /**< SCIP data structure */
6615 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
6616 	   SCIP_CONS*            cons,               /**< constraint which is propagated */
6617 	   SCIP_BT*              tree,               /**< binary tree constaining the theta and lambda sets */
6618 	   SCIP_BTNODE**         leaves,             /**< array of all leaves for each job one */
6619 	   int                   capacity,           /**< cumulative capacity */
6620 	   int                   ncands,             /**< number of candidates */
6621 	   SCIP_Bool             propest,            /**< should the earliest start times be propagated, otherwise the latest completion times */
6622 	   int                   shift,              /**< shift applied to all jobs before adding them to the tree */
6623 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
6624 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6625 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
6626 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
6627 	   )
6628 	{
6629 	   SCIP_NODEDATA* rootdata;
6630 	   int j;
6631 	
6632 	   assert(!SCIPbtIsEmpty(tree));
6633 	
6634 	   rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6635 	   assert(rootdata != NULL);
6636 	
6637 	   /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6638 	   for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6639 	   {
6640 	      SCIP_NODEDATA* nodedata;
6641 	
6642 	      if( SCIPbtnodeIsRoot(leaves[j]) )
6643 	         break;
6644 	
6645 	      nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6646 	      assert(nodedata->est != -1);
6647 	
6648 	      /* check if the root lambda envelop exeeds the available capacity */
6649 	      while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6650 	      {
6651 	         SCIP_BTNODE** omegaset;
6652 	         SCIP_BTNODE* leaf;
6653 	         SCIP_NODEDATA* leafdata;
6654 	         int nelements;
6655 	         int energy;
6656 	         int newest;
6657 	         int est;
6658 	         int lct;
6659 	
6660 	         assert(!(*cutoff));
6661 	
6662 	         /* find responsible leaf for the lambda envelope */
6663 	         leaf = findResponsibleLambdaLeafTraceEnvelop(SCIPbtGetRoot(tree));
6664 	         assert(leaf != NULL);
6665 	         assert(SCIPbtnodeIsLeaf(leaf));
6666 	
6667 	         leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6668 	         assert(leafdata != NULL);
6669 	         assert(!leafdata->intheta);
6670 	         assert(leafdata->duration > 0);
6671 	         assert(leafdata->est >= 0);
6672 	
6673 	         /* check if the job has to be removed since its latest completion is to large */
6674 	         if( leafdata->est + leafdata->duration >= nodedata->lct )
6675 	         {
6676 	            SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6677 	
6678 	            /* the root might changed therefore we need to collect the new root node data */
6679 	            rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6680 	            assert(rootdata != NULL);
6681 	
6682 	            continue;
6683 	         }
6684 	
6685 	         /* compute omega set */
6686 	         SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6687 	
6688 	         nelements = 0;
6689 	         est = INT_MAX;
6690 	         lct = INT_MIN;
6691 	         energy = 0;
6692 	
6693 	         /* collect the omega set from theta set */
6694 	         traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6695 	         assert(nelements > 0);
6696 	         assert(nelements < ncands);
6697 	
6698 	         newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6699 	
6700 	         /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6701 	         if( newest > lct )
6702 	         {
6703 	            SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6704 	
6705 	            /* analyze over load */
6706 	            SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements,  est, lct, 0, propest, shift,
6707 	                  conshdlrdata->usebdwidening, initialized, explanation) );
6708 	            (*cutoff) = TRUE;
6709 	
6710 	            /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6711 	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6712 	         }
6713 	         else if( newest > 0 )
6714 	         {
6715 	            SCIP_Bool infeasible;
6716 	            SCIP_Bool tightened;
6717 	            INFERINFO inferinfo;
6718 	
6719 	            if( propest )
6720 	            {
6721 	               /* constuct inference information; store used propagation rule and the the time window of the omega set */
6722 	               inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6723 	
6724 	               SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6725 	                  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6726 	
6727 	               if( inferInfoIsValid(inferinfo) )
6728 	               {
6729 	                  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6730 	                        cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6731 	               }
6732 	               else
6733 	               {
6734 	                  SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6735 	                        TRUE, &infeasible, &tightened) );
6736 	               }
6737 	
6738 	               /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6739 	               SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nlbedgefinder++ );
6740 	            }
6741 	            else
6742 	            {
6743 	               /* constuct inference information; store used propagation rule and the the time window of the omega set */
6744 	               inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6745 	
6746 	               SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6747 	                  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6748 	
6749 	               if( inferInfoIsValid(inferinfo) )
6750 	               {
6751 	                  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6752 	                        cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6753 	               }
6754 	               else
6755 	               {
6756 	                  SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6757 	                        TRUE, &infeasible, &tightened) );
6758 	               }
6759 	
6760 	               /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6761 	               SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nubedgefinder++ );
6762 	            }
6763 	
6764 	            /* adjust the earliest start time */
6765 	            if( tightened )
6766 	            {
6767 	               leafdata->est = newest;
6768 	               (*nchgbds)++;
6769 	            }
6770 	
6771 	            if( infeasible )
6772 	            {
6773 	               /* initialize conflict analysis if conflict analysis is applicable */
6774 	               if( SCIPisConflictAnalysisApplicable(scip) )
6775 	               {
6776 	                  int i;
6777 	
6778 	                  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6779 	
6780 	                  SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
6781 	
6782 	                  /* add lower and upper bound of variable which leads to the infeasibilty */
6783 	                  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6784 	                  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6785 	
6786 	                  if( explanation != NULL )
6787 	                     explanation[leafdata->idx] = TRUE;
6788 	
6789 	                  /* add lower and upper bound of variable which lead to the infeasibilty */
6790 	                  for( i = 0; i < nelements; ++i )
6791 	                  {
6792 	                     nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6793 	                     assert(nodedata != NULL);
6794 	
6795 	                     SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6796 	                     SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6797 	
6798 	                     if( explanation != NULL )
6799 	                        explanation[nodedata->idx] = TRUE;
6800 	                  }
6801 	
6802 	                  (*initialized) = TRUE;
6803 	               }
6804 	
6805 	               (*cutoff) = TRUE;
6806 	
6807 	               /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6808 	               SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6809 	            }
6810 	         }
6811 	
6812 	         /* free omegaset array */
6813 	         SCIPfreeBufferArray(scip, &omegaset);
6814 	
6815 	         /* delete responsible leaf from lambda */
6816 	         SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6817 	
6818 	         /* the root might changed therefore we need to collect the new root node data */
6819 	         rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6820 	         assert(rootdata != NULL);
6821 	      }
6822 	
6823 	      /* move current job j from the theta set into the lambda set */
6824 	      SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6825 	   }
6826 	
6827 	   return SCIP_OKAY;
6828 	}
6829 	
6830 	/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6831 	 *
6832 	 *  @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6833 	 *        Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6834 	 *        Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6835 	 */
6836 	static
6837 	SCIP_RETCODE checkOverloadViaThetaTree(
6838 	   SCIP*                 scip,               /**< SCIP data structure */
6839 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
6840 	   int                   nvars,              /**< number of start time variables (activities) */
6841 	   SCIP_VAR**            vars,               /**< array of start time variables */
6842 	   int*                  durations,          /**< array of durations */
6843 	   int*                  demands,            /**< array of demands */
6844 	   int                   capacity,           /**< cumulative capacity */
6845 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
6846 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
6847 	   SCIP_CONS*            cons,               /**< constraint which is propagated */
6848 	   SCIP_Bool             propest,            /**< should the earliest start times be propagated, otherwise the latest completion times */
6849 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
6850 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6851 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
6852 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
6853 	   )
6854 	{
6855 	   SCIP_NODEDATA* nodedatas;
6856 	   SCIP_BTNODE** leaves;
6857 	   SCIP_BT* tree;
6858 	   int* nodedataidx;
6859 	
6860 	   int totalenergy;
6861 	   int nnodedatas;
6862 	   int ninsertcands;
6863 	   int ncands;
6864 	
6865 	   int shift;
6866 	   int idx = -1;
6867 	   int j;
6868 	
6869 	   assert(scip != NULL);
6870 	   assert(cons != NULL);
6871 	   assert(initialized != NULL);
6872 	   assert(cutoff != NULL);
6873 	   assert(*cutoff == FALSE);
6874 	
6875 	   SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6876 	
6877 	   SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6878 	   SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6879 	   SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6880 	
6881 	   ncands = 0;
6882 	   totalenergy = 0;
6883 	
6884 	   SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6885 	
6886 	   /* compute the shift which we apply to compute .... latest completion time of all jobs */
6887 	   if( propest )
6888 	      shift = 0;
6889 	   else
6890 	   {
6891 	      shift = 0;
6892 	
6893 	      /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6894 	       * earliest start time propagation to handle the latest completion times
6895 	       */
6896 	      for( j = 0; j < nvars; ++j )
6897 	      {
6898 	         int lct;
6899 	
6900 	         lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6901 	         shift = MAX(shift, lct);
6902 	      }
6903 	   }
6904 	
6905 	   /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6906 	    * horizon
6907 	    */
6908 	   for( j = 0; j < nvars; ++j )
6909 	   {
6910 	      SCIP_NODEDATA* nodedata;
6911 	      SCIP_VAR* var;
6912 	      int duration;
6913 	      int leftadjust;
6914 	      int rightadjust;
6915 	      int energy;
6916 	      int est;
6917 	      int lct;
6918 	
6919 	      var = vars[j];
6920 	      assert(var != NULL);
6921 	
6922 	      duration = durations[j];
6923 	      assert(duration > 0);
6924 	
6925 	      leftadjust = 0;
6926 	      rightadjust = 0;
6927 	
6928 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6929 	      lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6930 	
6931 	      /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6932 	       * effective horizon [hmin,hmax)
6933 	       */
6934 	      if( conshdlrdata->useadjustedjobs )
6935 	      {
6936 	         if( est < hmin )
6937 	         {
6938 	            leftadjust = (hmin - est);
6939 	            est = hmin;
6940 	         }
6941 	         if( lct > hmax )
6942 	         {
6943 	            rightadjust = (lct - hmax);
6944 	            lct = hmax;
6945 	         }
6946 	
6947 	         /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6948 	          * with the effective time horizon
6949 	          */
6950 	         if( duration - leftadjust - rightadjust <= 0 )
6951 	            continue;
6952 	      }
6953 	      else if( est < hmin || lct > hmax )
6954 	         continue;
6955 	
6956 	      energy = demands[j] * (duration - leftadjust - rightadjust);
6957 	      assert(energy > 0);
6958 	
6959 	      totalenergy += energy;
6960 	
6961 	      /* flip earliest start time and latest completion time */
6962 	      if( !propest )
6963 	      {
6964 	         SCIPswapInts(&est, &lct);
6965 	
6966 	         /* shift earliest start time and latest completion time */
6967 	         lct = shift - lct;
6968 	         est = shift - est;
6969 	      }
6970 	      else
6971 	      {
6972 	         /* shift earliest start time and latest completion time */
6973 	         lct = lct - shift;
6974 	         est = est - shift;
6975 	      }
6976 	      assert(est < lct);
6977 	      assert(est >= 0);
6978 	      assert(lct >= 0);
6979 	
6980 	      /* create search node data */
6981 	      nodedata = &nodedatas[ncands];
6982 	      nodedataidx[ncands] = ncands;
6983 	      ++ncands;
6984 	
6985 	      /* initialize search node data */
6986 	      /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6987 	      nodedata->key = est + j / (2.0 * nvars);
6988 	      nodedata->var = var;
6989 	      nodedata->est = est;
6990 	      nodedata->lct = lct;
6991 	      nodedata->demand = demands[j];
6992 	      nodedata->duration = duration;
6993 	      nodedata->leftadjust = leftadjust;
6994 	      nodedata->rightadjust = rightadjust;
6995 	
6996 	      /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6997 	       * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6998 	       * particular time interval [a,b] against the time interval [0,b].
6999 	       */
7000 	      nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
7001 	      nodedata->energytheta = energy;
7002 	      nodedata->enveloplambda = -1;
7003 	      nodedata->energylambda = -1;
7004 	
7005 	      nodedata->idx = j;
7006 	      nodedata->intheta = TRUE;
7007 	   }
7008 	
7009 	   nnodedatas = ncands;
7010 	
7011 	   /* sort (non-decreasing) the jobs w.r.t. latest completion times */
7012 	   SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
7013 	
7014 	   ninsertcands = 0;
7015 	
7016 	   /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
7017 	    * the root envelop detects an overload
7018 	    */
7019 	   for( j = 0; j < ncands; ++j )
7020 	   {
7021 	      SCIP_BTNODE* leaf;
7022 	      SCIP_NODEDATA* rootdata;
7023 	
7024 	      idx = nodedataidx[j];
7025 	
7026 	      /* check if the new job opens a time window which size is so large that it offers more energy than the total
7027 	       * energy of all candidate jobs. If so we skip that one.
7028 	       */
7029 	      if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
7030 	      {
7031 	         /* set the earliest start time to minus one to mark that candidate to be not used */
7032 	         nodedatas[idx].est = -1;
7033 	         continue;
7034 	      }
7035 	
7036 	      /* create search node */
7037 	      SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
7038 	
7039 	      /* insert new node into the theta set and updete the envelops */
7040 	      SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
7041 	      assert(nnodedatas <= 2*nvars);
7042 	
7043 	      /* move the inserted candidates together */
7044 	      leaves[ninsertcands] = leaf;
7045 	      ninsertcands++;
7046 	
7047 	      assert(!SCIPbtIsEmpty(tree));
7048 	      rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
7049 	      assert(rootdata != NULL);
7050 	
7051 	      /* check if the theta set envelops exceeds the available capacity */
7052 	      if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
7053 	      {
7054 	         SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
7055 	         (*cutoff) = TRUE;
7056 	
7057 	         /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7058 	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7059 	
7060 	         break;
7061 	      }
7062 	   }
7063 	
7064 	   /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7065 	   if( *cutoff )
7066 	   {
7067 	      int glbenery;
7068 	      int est;
7069 	      int lct;
7070 	
7071 	      glbenery = 0;
7072 	      assert( 0 <= idx );
7073 	      est = nodedatas[idx].est;
7074 	      lct = nodedatas[idx].lct;
7075 	
7076 	      /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7077 	       * which led to an overload
7078 	       */
7079 	      for( j = j+1; j < ncands; ++j )
7080 	      {
7081 	         SCIP_NODEDATA* nodedata;
7082 	         int duration;
7083 	         int glbest;
7084 	         int glblct;
7085 	
7086 	         idx = nodedataidx[j];
7087 	         nodedata = &nodedatas[idx];
7088 	         assert(nodedata != NULL);
7089 	
7090 	         duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7091 	
7092 	         /* get latest start time */
7093 	         glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7094 	         glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7095 	
7096 	         /* check if parts of the jobs run with the time window defined by the last inserted job */
7097 	         if( glbest < est )
7098 	            duration -= (est - glbest);
7099 	
7100 	         if( glblct > lct )
7101 	            duration -= (glblct - lct);
7102 	
7103 	         if( duration > 0 )
7104 	         {
7105 	            glbenery += nodedata->demand * duration;
7106 	
7107 	            if( explanation != NULL )
7108 	               explanation[nodedata->idx] = TRUE;
7109 	         }
7110 	      }
7111 	
7112 	      /* analyze the overload */
7113 	      SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7114 	            conshdlrdata->usebdwidening, initialized, explanation) );
7115 	   }
7116 	   else if( ninsertcands > 1 && conshdlrdata->efinfer )
7117 	   {
7118 	      /* if we have more than one job insterted and edge-finding should be performed we do it */
7119 	      SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7120 	            propest, shift, initialized, explanation, nchgbds, cutoff) );
7121 	   }
7122 	
7123 	   /* free theta tree */
7124 	   SCIPbtFree(&tree);
7125 	
7126 	   /* free buffer arrays */
7127 	   SCIPfreeBufferArray(scip, &leaves);
7128 	   SCIPfreeBufferArray(scip, &nodedataidx);
7129 	   SCIPfreeBufferArray(scip, &nodedatas);
7130 	
7131 	   return SCIP_OKAY;
7132 	}
7133 	
7134 	/** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7135 	 *
7136 	 *  @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7137 	 *        Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7138 	 *        Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7139 	 */
7140 	static
7141 	SCIP_RETCODE propagateEdgeFinding(
7142 	   SCIP*                 scip,               /**< SCIP data structure */
7143 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
7144 	   int                   nvars,              /**< number of start time variables (activities) */
7145 	   SCIP_VAR**            vars,               /**< array of start time variables */
7146 	   int*                  durations,          /**< array of durations */
7147 	   int*                  demands,            /**< array of demands */
7148 	   int                   capacity,           /**< cumulative capacity */
7149 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
7150 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
7151 	   SCIP_CONS*            cons,               /**< constraint which is propagated */
7152 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
7153 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7154 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
7155 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
7156 	   )
7157 	{
7158 	   /* check if a cutoff was already detected */
7159 	   if( (*cutoff) )
7160 	      return SCIP_OKAY;
7161 	
7162 	   /* check if at least the basic overload checking should be preformed */
7163 	   if( !conshdlrdata->efcheck )
7164 	      return SCIP_OKAY;
7165 	
7166 	   /* check for overload, which may result in a cutoff */
7167 	   SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7168 	         cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7169 	
7170 	   /* check if a cutoff was detected */
7171 	   if( (*cutoff) )
7172 	      return SCIP_OKAY;
7173 	
7174 	   /* check if bound should be infer */
7175 	   if( !conshdlrdata->efinfer )
7176 	      return SCIP_OKAY;
7177 	
7178 	   /* check for overload, which may result in a cutoff */
7179 	   SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7180 	         cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7181 	
7182 	   return SCIP_OKAY;
7183 	}
7184 	
7185 	/** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7186 	 *  with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7187 	 *  event points
7188 	 */
7189 	static
7190 	SCIP_RETCODE consCheckRedundancy(
7191 	   SCIP*                 scip,               /**< SCIP data structure */
7192 	   int                   nvars,              /**< number of start time variables (activities) */
7193 	   SCIP_VAR**            vars,               /**< array of start time variables */
7194 	   int*                  durations,          /**< array of durations */
7195 	   int*                  demands,            /**< array of demands */
7196 	   int                   capacity,           /**< cumulative capacity */
7197 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
7198 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
7199 	   SCIP_Bool*            redundant           /**< pointer to store whether this constraint is redundant */
7200 	   )
7201 	{
7202 	   SCIP_VAR* var;
7203 	   int* starttimes;              /* stores when each job is starting */
7204 	   int* endtimes;                /* stores when each job ends */
7205 	   int* startindices;            /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7206 	   int* endindices;              /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7207 	
7208 	   int lb;
7209 	   int ub;
7210 	   int freecapacity;             /* remaining capacity */
7211 	   int curtime;                  /* point in time which we are just checking */
7212 	   int endindex;                 /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7213 	   int njobs;
7214 	   int j;
7215 	
7216 	   assert(scip != NULL);
7217 	   assert(redundant != NULL);
7218 	
7219 	   (*redundant) = TRUE;
7220 	
7221 	   /* if no activities are associated with this cumulative then this constraint is redundant */
7222 	   if( nvars == 0 )
7223 	      return SCIP_OKAY;
7224 	
7225 	   assert(vars != NULL);
7226 	
7227 	   SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7228 	   SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7229 	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7230 	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7231 	
7232 	   njobs = 0;
7233 	
7234 	   /* assign variables, start and endpoints to arrays */
7235 	   for( j = 0; j < nvars; ++j )
7236 	   {
7237 	      assert(durations[j] > 0);
7238 	      assert(demands[j] > 0);
7239 	
7240 	      var = vars[j];
7241 	      assert(var != NULL);
7242 	
7243 	      lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7244 	      ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7245 	
7246 	      /* check if jobs runs completely outside of the effective time horizon */
7247 	      if( lb >= hmax || ub + durations[j] <= hmin )
7248 	         continue;
7249 	
7250 	      starttimes[njobs] = MAX(lb, hmin);
7251 	      startindices[njobs] = j;
7252 	
7253 	      endtimes[njobs] =  MIN(ub + durations[j], hmax);
7254 	      endindices[njobs] = j;
7255 	      assert(starttimes[njobs] <= endtimes[njobs]);
7256 	      njobs++;
7257 	   }
7258 	
7259 	   /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7260 	   SCIPsortIntInt(starttimes, startindices, njobs);
7261 	   SCIPsortIntInt(endtimes, endindices, njobs);
7262 	
7263 	   endindex = 0;
7264 	   freecapacity = capacity;
7265 	
7266 	   /* check each start point of a job whether the capacity is violated or not */
7267 	   for( j = 0; j < njobs; ++j )
7268 	   {
7269 	      curtime = starttimes[j];
7270 	
7271 	      /* stop checking, if time point is above hmax */
7272 	      if( curtime >= hmax )
7273 	         break;
7274 	
7275 	      /* subtract all capacity needed up to this point */
7276 	      freecapacity -= demands[startindices[j]];
7277 	      while( j+1 < njobs && starttimes[j+1] == curtime )
7278 	      {
7279 	         ++j;
7280 	         freecapacity -= demands[startindices[j]];
7281 	      }
7282 	
7283 	      /* free all capacity usages of jobs the are no longer running */
7284 	      while( endtimes[endindex] <= curtime )
7285 	      {
7286 	         freecapacity += demands[endindices[endindex]];
7287 	         ++endindex;
7288 	      }
7289 	      assert(freecapacity <= capacity);
7290 	
7291 	      /* check freecapacity to be smaller than zero */
7292 	      if( freecapacity < 0 && curtime >= hmin )
7293 	      {
7294 	         (*redundant) = FALSE;
7295 	         break;
7296 	      }
7297 	   } /*lint --e{850}*/
7298 	
7299 	   /* free all buffer arrays */
7300 	   SCIPfreeBufferArray(scip, &endindices);
7301 	   SCIPfreeBufferArray(scip, &startindices);
7302 	   SCIPfreeBufferArray(scip, &endtimes);
7303 	   SCIPfreeBufferArray(scip, &starttimes);
7304 	
7305 	   return SCIP_OKAY;
7306 	}
7307 	
7308 	/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7309 	 *  completion time
7310 	 */
7311 	static
7312 	SCIP_RETCODE createCoreProfile(
7313 	   SCIP*                 scip,               /**< SCIP data structure */
7314 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
7315 	   SCIP_PROFILE*         profile,            /**< resource profile */
7316 	   int                   nvars,              /**< number of variables (jobs) */
7317 	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
7318 	   int*                  durations,          /**< array containing corresponding durations */
7319 	   int*                  demands,            /**< array containing corresponding demands */
7320 	   int                   capacity,           /**< cumulative capacity */
7321 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
7322 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
7323 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
7324 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7325 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
7326 	   )
7327 	{
7328 	   int v;
7329 	
7330 	   /* insert all cores */
7331 	   for( v = 0; v < nvars; ++v )
7332 	   {
7333 	      SCIP_VAR* var;
7334 	      SCIP_Bool infeasible;
7335 	      int duration;
7336 	      int demand;
7337 	      int begin;
7338 	      int end;
7339 	      int est;
7340 	      int lst;
7341 	      int pos;
7342 	
7343 	      var = vars[v];
7344 	      assert(var != NULL);
7345 	      assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7346 	      assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7347 	
7348 	      duration = durations[v];
7349 	      assert(duration > 0);
7350 	
7351 	      demand =  demands[v];
7352 	      assert(demand > 0);
7353 	
7354 	      /* collect earliest and latest start time */
7355 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7356 	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7357 	
7358 	      /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7359 	      if( lst + duration <= hmin || est >= hmax )
7360 	         continue;
7361 	
7362 	      /* compute core interval w.r.t. effective time horizon */
7363 	      begin = MAX(hmin, lst);
7364 	      end = MIN(hmax, est + duration);
7365 	
7366 	      /* check if a core exists */
7367 	      if( begin >= end )
7368 	         continue;
7369 	
7370 	      SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7371 	         SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7372 	
7373 	      /* insert the core into core resource profile (complexity O(log n)) */
7374 	      SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7375 	
7376 	      /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7377 	      if( infeasible )
7378 	      {
7379 	         assert(begin <= SCIPprofileGetTime(profile, pos));
7380 	         assert(end > SCIPprofileGetTime(profile, pos));
7381 	
7382 	         /* use conflict analysis to analysis the core insertion which was infeasible */
7383 	         SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7384 	               var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7385 	
7386 	         if( explanation != NULL )
7387 	            explanation[v] = TRUE;
7388 	
7389 	         (*cutoff) = TRUE;
7390 	
7391 	         /* for the statistic we count the number of times a cutoff was detected due the time-time */
7392 	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7393 	
7394 	         break;
7395 	      }
7396 	   }
7397 	
7398 	   return SCIP_OKAY;
7399 	}
7400 	
7401 	/** propagate the cumulative condition */
7402 	static
7403 	SCIP_RETCODE propagateCumulativeCondition(
7404 	   SCIP*                 scip,               /**< SCIP data structure */
7405 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
7406 	   SCIP_PRESOLTIMING     presoltiming,       /**< current presolving timing */
7407 	   int                   nvars,              /**< number of start time variables (activities) */
7408 	   SCIP_VAR**            vars,               /**< array of start time variables */
7409 	   int*                  durations,          /**< array of durations */
7410 	   int*                  demands,            /**< array of demands */
7411 	   int                   capacity,           /**< cumulative capacity */
7412 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
7413 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
7414 	   SCIP_CONS*            cons,               /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7415 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
7416 	   SCIP_Bool*            redundant,          /**< pointer to store if the constraint is redundant */
7417 	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
7418 	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7419 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
7420 	   )
7421 	{
7422 	   SCIP_PROFILE* profile;
7423 	
7424 	   SCIP_RETCODE retcode = SCIP_OKAY;
7425 	
7426 	   assert(nchgbds != NULL);
7427 	   assert(initialized != NULL);
7428 	   assert(cutoff != NULL);
7429 	   assert(!(*cutoff));
7430 	
7431 	   /**@todo avoid always sorting the variable array */
7432 	
7433 	   /* check if the constraint is redundant */
7434 	   SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7435 	
7436 	   if( *redundant )
7437 	      return SCIP_OKAY;
7438 	
7439 	   /* create an empty resource profile for profiling the cores of the jobs */
7440 	   SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7441 	
7442 	   /* create core profile (compulsory parts) */
7443 	   SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7444 	         initialized, explanation, cutoff), TERMINATE );
7445 	
7446 	   /* propagate the job cores until nothing else can be detected */
7447 	   if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7448 	   {
7449 	      SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7450 	            nchgbds, initialized, explanation, cutoff), TERMINATE );
7451 	   }
7452 	
7453 	   /* run edge finding propagator */
7454 	   if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7455 	   {
7456 	      SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7457 	            cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7458 	   }
7459 	
7460 	   /* run time-table edge-finding propagator */
7461 	   if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7462 	   {
7463 	      SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7464 	            nchgbds, initialized, explanation, cutoff), TERMINATE );
7465 	   }
7466 	   /* free resource profile */
7467 	TERMINATE:
7468 	   SCIPprofileFree(&profile);
7469 	
7470 	   return retcode;
7471 	}
7472 	
7473 	/** propagate the cumulative constraint */
7474 	static
7475 	SCIP_RETCODE propagateCons(
7476 	   SCIP*                 scip,               /**< SCIP data structure */
7477 	   SCIP_CONS*            cons,               /**< constraint to propagate */
7478 	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
7479 	   SCIP_PRESOLTIMING     presoltiming,       /**< current presolving timing */
7480 	   int*                  nchgbds,            /**< pointer to store the number of bound changes */
7481 	   int*                  ndelconss,          /**< pointer to store the number of deleted constraints */
7482 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
7483 	   )
7484 	{
7485 	   SCIP_CONSDATA* consdata;
7486 	   SCIP_Bool initialized;
7487 	   SCIP_Bool redundant;
7488 	   int oldnchgbds;
7489 	
7490 	   assert(scip != NULL);
7491 	   assert(cons != NULL);
7492 	
7493 	   consdata = SCIPconsGetData(cons);
7494 	   assert(consdata != NULL);
7495 	
7496 	   oldnchgbds = *nchgbds;
7497 	   initialized = FALSE;
7498 	   redundant = FALSE;
7499 	
7500 	   if( SCIPconsIsDeleted(cons) )
7501 	   {
7502 	      assert(SCIPinProbing(scip));
7503 	      return SCIP_OKAY;
7504 	   }
7505 	
7506 	   /* if the constraint marked to be propagated, do nothing */
7507 	   if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7508 	      return SCIP_OKAY;
7509 	
7510 	   SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7511 	         consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7512 	         consdata->hmin, consdata->hmax, cons,
7513 	         nchgbds, &redundant, &initialized, NULL, cutoff) );
7514 	
7515 	   if( redundant )
7516 	   {
7517 	      SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7518 	         SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7519 	
7520 	      if( !SCIPinProbing(scip) )
7521 	      {
7522 	         SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7523 	         (*ndelconss)++;
7524 	      }
7525 	   }
7526 	   else
7527 	   {
7528 	      if( initialized )
7529 	      {
7530 	         /* run conflict analysis since it was initialized */
7531 	         assert(*cutoff == TRUE);
7532 	         SCIPdebugMsg(scip, "start conflict analysis\n");
7533 	         SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7534 	      }
7535 	
7536 	      /* if successful, reset age of constraint */
7537 	      if( *cutoff || *nchgbds > oldnchgbds )
7538 	      {
7539 	         SCIP_CALL( SCIPresetConsAge(scip, cons) );
7540 	      }
7541 	      else
7542 	      {
7543 	         /* mark the constraint to be propagated */
7544 	         consdata->propagated = TRUE;
7545 	      }
7546 	   }
7547 	
7548 	   return SCIP_OKAY;
7549 	}
7550 	
7551 	/** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7552 	 * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7553 	 * be realize as domain reduction. Otherwise we do nothing
7554 	 */
7555 	static
7556 	SCIP_RETCODE applyProbingVar(
7557 	   SCIP*                 scip,               /**< SCIP data structure */
7558 	   SCIP_VAR**            vars,               /**< problem variables */
7559 	   int                   nvars,              /**< number of problem variables */
7560 	   int                   probingpos,         /**< variable number to apply probing on */
7561 	   SCIP_Real             leftub,             /**< upper bound of probing variable in left branch */
7562 	   SCIP_Real             rightlb,            /**< lower bound of probing variable in right branch */
7563 	   SCIP_Real*            leftimpllbs,        /**< lower bounds after applying implications and cliques in left branch, or NULL */
7564 	   SCIP_Real*            leftimplubs,        /**< upper bounds after applying implications and cliques in left branch, or NULL */
7565 	   SCIP_Real*            leftproplbs,        /**< lower bounds after applying domain propagation in left branch */
7566 	   SCIP_Real*            leftpropubs,        /**< upper bounds after applying domain propagation in left branch */
7567 	   SCIP_Real*            rightimpllbs,       /**< lower bounds after applying implications and cliques in right branch, or NULL */
7568 	   SCIP_Real*            rightimplubs,       /**< upper bounds after applying implications and cliques in right branch, or NULL */
7569 	   SCIP_Real*            rightproplbs,       /**< lower bounds after applying domain propagation in right branch */
7570 	   SCIP_Real*            rightpropubs,       /**< upper bounds after applying domain propagation in right branch */
7571 	   int*                  nfixedvars,         /**< pointer to counter which is increased by the number of deduced variable fixations */
7572 	   SCIP_Bool*            success,            /**< buffer to store whether a probing succeed to dual fix the variable */
7573 	   SCIP_Bool*            cutoff              /**< buffer to store whether a cutoff is detected */
7574 	   )
7575 	{
7576 	   SCIP_VAR* var;
7577 	   SCIP_Bool tightened;
7578 	
7579 	   assert(probingpos >= 0);
7580 	   assert(probingpos < nvars);
7581 	   assert(success != NULL);
7582 	   assert(cutoff != NULL);
7583 	
7584 	   var = vars[probingpos];
7585 	   assert(var != NULL);
7586 	   assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7587 	   assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7588 	   assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7589 	   assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7590 	
7591 	   (*success) = FALSE;
7592 	
7593 	   if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7594 	      return SCIP_OKAY;
7595 	
7596 	   /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7597 	   SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7598 	         leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7599 	
7600 	   if( (*cutoff) )
7601 	   {
7602 	      /* note that cutoff may occur if presolving has not been executed fully */
7603 	      SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7604 	
7605 	      if( tightened )
7606 	      {
7607 	         (*success) =TRUE;
7608 	         (*nfixedvars)++;
7609 	      }
7610 	
7611 	      return SCIP_OKAY;
7612 	   }
7613 	
7614 	   /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7615 	    * presolving has not been executed fully
7616 	    */
7617 	   if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7618 	   {
7619 	      /* note that cutoff may occur if presolving has not been executed fully */
7620 	      SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7621 	
7622 	      if( tightened )
7623 	      {
7624 	         (*success) = TRUE;
7625 	         (*nfixedvars)++;
7626 	      }
7627 	
7628 	      return SCIP_OKAY;
7629 	   }
7630 	
7631 	   /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7632 	   SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7633 	         rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7634 	
7635 	   if( (*cutoff) )
7636 	   {
7637 	      /* note that cutoff may occur if presolving has not been executed fully */
7638 	      SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7639 	
7640 	      if( tightened )
7641 	      {
7642 	         (*success) =TRUE;
7643 	         (*nfixedvars)++;
7644 	      }
7645 	
7646 	      return SCIP_OKAY;
7647 	   }
7648 	
7649 	   return SCIP_OKAY;
7650 	}
7651 	
7652 	/** is it possible, to round variable down w.r.t. objective function */
7653 	static
7654 	SCIP_RETCODE varMayRoundDown(
7655 	   SCIP*                 scip,               /**< SCIP data structure */
7656 	   SCIP_VAR*             var,                /**< problem variable */
7657 	   SCIP_Bool*            roundable           /**< pointer to store if the variable can be rounded down */
7658 	   )
7659 	{
7660 	   SCIP_Real objval;
7661 	   int scalar;
7662 	
7663 	   assert(roundable != NULL);
7664 	
7665 	   *roundable = TRUE;
7666 	
7667 	   /* a fixed variable can be definition always be safely rounded */
7668 	   if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
7669 	      return SCIP_OKAY;
7670 	
7671 	   /* in case the variable is not active we need to check the object coefficient of the active variable */
7672 	   if( !SCIPvarIsActive(var) )
7673 	   {
7674 	      SCIP_VAR* actvar;
7675 	      int constant;
7676 	
7677 	      actvar = var;
7678 	
7679 	      SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7680 	      assert(scalar != 0);
7681 	
7682 	      objval = scalar * SCIPvarGetObj(actvar);
7683 	   } /*lint !e438*/
7684 	   else
7685 	   {
7686 	      scalar = 1;
7687 	      objval = SCIPvarGetObj(var);
7688 	   }
7689 	
7690 	   /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7691 	    * (the transformed problem is always a minimization problem)
7692 	    *
7693 	    * @note that we need to check this condition w.r.t. active variable space
7694 	    */
7695 	   if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7696 	      *roundable = FALSE;
7697 	
7698 	   return SCIP_OKAY;
7699 	}
7700 	
7701 	/** is it possible, to round variable up w.r.t. objective function */
7702 	static
7703 	SCIP_RETCODE varMayRoundUp(
7704 	   SCIP*                 scip,               /**< SCIP data structure */
7705 	   SCIP_VAR*             var,                /**< problem variable */
7706 	   SCIP_Bool*            roundable           /**< pointer to store if the variable can be rounded down */
7707 	   )
7708 	{
7709 	   SCIP_Real objval;
7710 	   int scalar;
7711 	
7712 	   assert(roundable != NULL);
7713 	
7714 	   *roundable = TRUE;
7715 	
7716 	   /* a fixed variable can be definition always be safely rounded */
7717 	   if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED )
7718 	      return SCIP_OKAY;
7719 	
7720 	   /* in case the variable is not active we need to check the object coefficient of the active variable */
7721 	   if( !SCIPvarIsActive(var) )
7722 	   {
7723 	      SCIP_VAR* actvar;
7724 	      int constant;
7725 	
7726 	      actvar = var;
7727 	
7728 	      SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7729 	      assert(scalar != 0);
7730 	
7731 	      objval = scalar * SCIPvarGetObj(actvar);
7732 	   } /*lint !e438*/
7733 	   else
7734 	   {
7735 	      scalar = 1;
7736 	      objval = SCIPvarGetObj(var);
7737 	   }
7738 	
7739 	   /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7740 	    * (the transformed problem is always a minimization problem)
7741 	    *
7742 	    * @note that we need to check this condition w.r.t. active variable space
7743 	    */
7744 	   if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7745 	      *roundable = FALSE;
7746 	
7747 	   return SCIP_OKAY;
7748 	}
7749 	
7750 	/** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7751 	 *  lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7752 	 *  values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7753 	 *  the only one locking this variable in the corresponding direction.
7754 	 */
7755 	static
7756 	SCIP_RETCODE computeAlternativeBounds(
7757 	   SCIP*                 scip,               /**< SCIP data structure */
7758 	   SCIP_CONS**           conss,              /**< array of cumulative constraint constraints */
7759 	   int                   nconss,             /**< number of cumulative constraints */
7760 	   SCIP_Bool             local,              /**< use local bounds effective horizon? */
7761 	   int*                  alternativelbs,     /**< alternative lower bounds */
7762 	   int*                  alternativeubs,     /**< alternative lower bounds */
7763 	   int*                  downlocks,          /**< number of constraints with down lock participating by the computation */
7764 	   int*                  uplocks             /**< number of constraints with up lock participating by the computation */
7765 	   )
7766 	{
7767 	   int nvars;
7768 	   int c;
7769 	   int v;
7770 	
7771 	   for( c = 0; c < nconss; ++c )
7772 	   {
7773 	      SCIP_CONSDATA* consdata;
7774 	      SCIP_CONS* cons;
7775 	      SCIP_VAR* var;
7776 	      int hmin;
7777 	      int hmax;
7778 	
7779 	      cons = conss[c];
7780 	      assert(cons != NULL);
7781 	
7782 	      /* ignore constraints which are already deletet and those which are not check constraints */
7783 	      if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7784 	         continue;
7785 	
7786 	      consdata = SCIPconsGetData(cons);
7787 	      assert(consdata != NULL);
7788 	      assert(consdata->nvars > 1);
7789 	
7790 	      /* compute the hmin and hmax */
7791 	      if( local )
7792 	      {
7793 	         SCIP_PROFILE* profile;
7794 	         SCIP_RETCODE retcode;
7795 	
7796 	         /* create empty resource profile with infinity resource capacity */
7797 	         SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7798 	
7799 	         /* create worst case resource profile */
7800 	         retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7801 	
7802 	         hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7803 	         hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7804 	
7805 	         /* free worst case profile */
7806 	         SCIPprofileFree(&profile);
7807 	
7808 	         if( retcode != SCIP_OKAY )
7809 	            return retcode;
7810 	      }
7811 	      else
7812 	      {
7813 	         hmin = consdata->hmin;
7814 	         hmax = consdata->hmax;
7815 	      }
7816 	
7817 	      consdata = SCIPconsGetData(cons);
7818 	      assert(consdata != NULL);
7819 	
7820 	      nvars = consdata->nvars;
7821 	
7822 	      for( v = 0; v < nvars; ++v )
7823 	      {
7824 	         int scalar;
7825 	         int constant;
7826 	         int idx;
7827 	
7828 	         var = consdata->vars[v];
7829 	         assert(var != NULL);
7830 	
7831 	         /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7832 	         assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7833 	
7834 	         /* ignore variable locally fixed variables */
7835 	         if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7836 	            continue;
7837 	
7838 	         SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7839 	         idx = SCIPvarGetProbindex(var);
7840 	         assert(idx >= 0);
7841 	
7842 	         /* first check lower bound fixing */
7843 	         if( consdata->downlocks[v] )
7844 	         {
7845 	            int ect;
7846 	            int est;
7847 	
7848 	            /* the variable has a down locked */
7849 	            est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7850 	            ect = est + consdata->durations[v];
7851 	
7852 	            if( ect <= hmin || hmin >= hmax )
7853 	               downlocks[idx]++;
7854 	            else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7855 	            {
7856 	               alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7857 	               downlocks[idx]++;
7858 	            }
7859 	         }
7860 	
7861 	         /* second check upper bound fixing */
7862 	         if( consdata->uplocks[v] )
7863 	         {
7864 	            int duration;
7865 	            int lct;
7866 	            int lst;
7867 	
7868 	            duration =  consdata->durations[v];
7869 	
7870 	            /* the variable has a up lock locked */
7871 	            lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7872 	            lct = lst + duration;
7873 	
7874 	            if( lst >= hmax || hmin >= hmax  )
7875 	               uplocks[idx]++;
7876 	            else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7877 	            {
7878 	               alternativeubs[idx] = ((hmax - 1 - constant) / scalar)  - duration;
7879 	               uplocks[idx]++;
7880 	            }
7881 	         }
7882 	      }
7883 	   }
7884 	
7885 	   return SCIP_OKAY;
7886 	}
7887 	
7888 	/** apply all fixings which are given by the alternative bounds */
7889 	static
7890 	SCIP_RETCODE applyAlternativeBoundsFixing(
7891 	   SCIP*                 scip,               /**< SCIP data structure */
7892 	   SCIP_VAR**            vars,               /**< array of active variables */
7893 	   int                   nvars,              /**< number of active variables */
7894 	   int*                  alternativelbs,     /**< alternative lower bounds */
7895 	   int*                  alternativeubs,     /**< alternative lower bounds */
7896 	   int*                  downlocks,          /**< number of constraints with down lock participating by the computation */
7897 	   int*                  uplocks,            /**< number of constraints with up lock participating by the computation */
7898 	   int*                  nfixedvars,         /**< pointer to counter which is increased by the number of deduced variable fixations */
7899 	   SCIP_Bool*            cutoff              /**< buffer to store whether a cutoff is detected */
7900 	   )
7901 	{
7902 	   SCIP_Real* downimpllbs;
7903 	   SCIP_Real* downimplubs;
7904 	   SCIP_Real* downproplbs;
7905 	   SCIP_Real* downpropubs;
7906 	   SCIP_Real* upimpllbs;
7907 	   SCIP_Real* upimplubs;
7908 	   SCIP_Real* upproplbs;
7909 	   SCIP_Real* uppropubs;
7910 	   int v;
7911 	
7912 	   /* get temporary memory for storing probing results */
7913 	   SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7914 	   SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7915 	   SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7916 	   SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7917 	   SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7918 	   SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7919 	   SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7920 	   SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7921 	
7922 	   for( v = 0; v < nvars; ++v )
7923 	   {
7924 	      SCIP_VAR* var;
7925 	      SCIP_Bool infeasible;
7926 	      SCIP_Bool fixed;
7927 	      SCIP_Bool roundable;
7928 	      int ub;
7929 	      int lb;
7930 	
7931 	      var = vars[v];
7932 	      assert(var != NULL);
7933 	
7934 	      /* ignore variables for which no alternative bounds have been computed */
7935 	      if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7936 	         continue;
7937 	
7938 	      lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7939 	      ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7940 	
7941 	      /* ignore fixed variables */
7942 	      if( ub - lb <= 0 )
7943 	         continue;
7944 	
7945 	      if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7946 	      {
7947 	         SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7948 	
7949 	         if( roundable )
7950 	         {
7951 	            if( alternativelbs[v] > ub )
7952 	            {
7953 	               SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7954 	               assert(!infeasible);
7955 	               assert(fixed);
7956 	
7957 	               (*nfixedvars)++;
7958 	
7959 	               /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7960 	                * constraints
7961 	                */
7962 	               SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7963 	            }
7964 	            else
7965 	            {
7966 	               SCIP_Bool success;
7967 	
7968 	               /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7969 	                * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7970 	                * infeasible we can apply the dual reduction; otherwise we do nothing
7971 	                */
7972 	               SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7973 	                     downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7974 	                     nfixedvars, &success, cutoff) );
7975 	
7976 	               if( success )
7977 	               {
7978 	                  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7979 	               }
7980 	            }
7981 	         }
7982 	      }
7983 	
7984 	      lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7985 	      ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7986 	
7987 	      /* ignore fixed variables */
7988 	      if( ub - lb <= 0 )
7989 	         continue;
7990 	
7991 	      if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7992 	      {
7993 	         SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7994 	
7995 	         if( roundable )
7996 	         {
7997 	            if( alternativeubs[v] < lb )
7998 	            {
7999 	               SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
8000 	               assert(!infeasible);
8001 	               assert(fixed);
8002 	
8003 	               (*nfixedvars)++;
8004 	
8005 	               /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
8006 	                * constraints
8007 	                */
8008 	               SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8009 	            }
8010 	            else
8011 	            {
8012 	               SCIP_Bool success;
8013 	
8014 	               /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
8015 	                * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
8016 	                * infeasible we can apply the dual reduction; otherwise we do nothing
8017 	                */
8018 	               SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
8019 	                     downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
8020 	                     nfixedvars, &success, cutoff) );
8021 	
8022 	               if( success )
8023 	               {
8024 	                  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8025 	               }
8026 	            }
8027 	         }
8028 	      }
8029 	   }
8030 	
8031 	   /* free temporary memory */
8032 	   SCIPfreeBufferArray(scip, &uppropubs);
8033 	   SCIPfreeBufferArray(scip, &upproplbs);
8034 	   SCIPfreeBufferArray(scip, &upimplubs);
8035 	   SCIPfreeBufferArray(scip, &upimpllbs);
8036 	   SCIPfreeBufferArray(scip, &downpropubs);
8037 	   SCIPfreeBufferArray(scip, &downproplbs);
8038 	   SCIPfreeBufferArray(scip, &downimplubs);
8039 	   SCIPfreeBufferArray(scip, &downimpllbs);
8040 	
8041 	   return SCIP_OKAY;
8042 	}
8043 	
8044 	/** propagate all constraints together */
8045 	static
8046 	SCIP_RETCODE propagateAllConss(
8047 	   SCIP*                 scip,               /**< SCIP data structure */
8048 	   SCIP_CONS**           conss,              /**< all cumulative constraint */
8049 	   int                   nconss,             /**< number of cumulative constraints */
8050 	   SCIP_Bool             local,              /**< use local bounds effective horizon? */
8051 	   int*                  nfixedvars,         /**< pointer to counter which is increased by the number of deduced variable fixations */
8052 	   SCIP_Bool*            cutoff,             /**< buffer to store whether a cutoff is detected */
8053 	   SCIP_Bool*            branched            /**< pointer to store if a branching was applied, or NULL to avoid branching */
8054 	   )
8055 	{  /*lint --e{715}*/
8056 	   SCIP_VAR** vars;
8057 	   int* downlocks;
8058 	   int* uplocks;
8059 	   int* alternativelbs;
8060 	   int* alternativeubs;
8061 	   int oldnfixedvars;
8062 	   int nvars;
8063 	   int v;
8064 	
8065 	   if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8066 	      return SCIP_OKAY;
8067 	
8068 	   nvars = SCIPgetNVars(scip);
8069 	   oldnfixedvars = *nfixedvars;
8070 	
8071 	   SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8072 	   SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8073 	   SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8074 	   SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8075 	   SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8076 	
8077 	   /* initialize arrays */
8078 	   for( v = 0; v < nvars; ++v )
8079 	   {
8080 	      downlocks[v] = 0;
8081 	      uplocks[v] = 0;
8082 	      alternativelbs[v] = INT_MAX;
8083 	      alternativeubs[v] = INT_MIN;
8084 	   }
8085 	
8086 	   /* compute alternative bounds */
8087 	   SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8088 	
8089 	   /* apply fixing which result of the alternative bounds directly */
8090 	   SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8091 	         nfixedvars, cutoff) );
8092 	
8093 	   if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8094 	   {
8095 	      SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8096 	   }
8097 	
8098 	   /* free all buffers */
8099 	   SCIPfreeBufferArray(scip, &alternativeubs);
8100 	   SCIPfreeBufferArray(scip, &alternativelbs);
8101 	   SCIPfreeBufferArray(scip, &uplocks);
8102 	   SCIPfreeBufferArray(scip, &downlocks);
8103 	   SCIPfreeBufferArray(scip, &vars);
8104 	
8105 	   return SCIP_OKAY;
8106 	}
8107 	
8108 	/**@} */
8109 	
8110 	/**@name Linear relaxations
8111 	 *
8112 	 * @{
8113 	 */
8114 	
8115 	/** creates covering cuts for jobs violating resource constraints */
8116 	static
8117 	SCIP_RETCODE createCoverCutsTimepoint(
8118 	   SCIP*                 scip,               /**< SCIP data structure */
8119 	   SCIP_CONS*            cons,               /**< constraint to be checked */
8120 	   int*                  startvalues,        /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8121 	   int                   time                /**< at this point in time covering constraints are valid */
8122 	   )
8123 	{
8124 	   SCIP_CONSDATA* consdata;
8125 	   SCIP_ROW* row;
8126 	   int* flexibleids;
8127 	   int* demands;
8128 	
8129 	   char rowname[SCIP_MAXSTRLEN];
8130 	
8131 	   int remainingcap;
8132 	   int smallcoversize;    /* size of a small cover */
8133 	   int bigcoversize;    /* size of a big cover */
8134 	   int nvars;
8135 	
8136 	   int nflexible;
8137 	   int sumdemand;            /* demand of all jobs up to a certain index */
8138 	   int j;
8139 	
8140 	   assert(cons != NULL);
8141 	
8142 	   /* get constraint data structure */
8143 	   consdata = SCIPconsGetData(cons);
8144 	   assert(consdata != NULL );
8145 	
8146 	   nvars = consdata->nvars;
8147 	
8148 	   /* sort jobs according to demands */
8149 	   SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8150 	   SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8151 	
8152 	   nflexible = 0;
8153 	   remainingcap = consdata->capacity;
8154 	
8155 	   /* get all jobs intersecting point 'time' with their bounds */
8156 	   for( j = 0; j < nvars; ++j )
8157 	   {
8158 	      int ub;
8159 	
8160 	      ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8161 	
8162 	      /* only add jobs to array if they intersect with point 'time' */
8163 	      if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8164 	      {
8165 	         /* if job is fixed, capacity has to be decreased */
8166 	         if( startvalues[j] == ub )
8167 	         {
8168 	            remainingcap -= consdata->demands[j];
8169 	         }
8170 	         else
8171 	         {
8172 	            demands[nflexible] = consdata->demands[j];
8173 	            flexibleids[nflexible] = j;
8174 	            ++nflexible;
8175 	         }
8176 	      }
8177 	   }
8178 	   assert(remainingcap >= 0);
8179 	
8180 	   /* sort demands and job ids */
8181 	   SCIPsortIntInt(demands, flexibleids, nflexible);
8182 	
8183 	   /*
8184 	    * version 1:
8185 	    * D_j := sum_i=0,...,j  d_i, finde j maximal, so dass D_j <= remainingcap
8186 	    * erzeuge cover constraint
8187 	    *
8188 	    */
8189 	
8190 	   /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8191 	   sumdemand = 0;
8192 	   j = 0;
8193 	
8194 	   while( j < nflexible && sumdemand <= remainingcap )
8195 	   {
8196 	      sumdemand += demands[j];
8197 	      j++;
8198 	   }
8199 	
8200 	   /* j jobs form a conflict, set coversize to 'j - 1' */
8201 	   bigcoversize = j-1;
8202 	   assert(sumdemand > remainingcap);
8203 	   assert(bigcoversize < nflexible);
8204 	
8205 	   /* - create a row for all jobs and their binary variables.
8206 	    * - at most coversize many binary variables of jobs can be set to one
8207 	    */
8208 	
8209 	   /* construct row name */
8210 	   (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8211 	   SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8212 	         SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8213 	   SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8214 	
8215 	   for( j = 0; j < nflexible; ++j )
8216 	   {
8217 	      SCIP_VAR** binvars;
8218 	      SCIP_Real* vals;
8219 	      int nbinvars;
8220 	      int idx;
8221 	      int start;
8222 	      int end;
8223 	      int lb;
8224 	      int ub;
8225 	      int b;
8226 	
8227 	      idx = flexibleids[j];
8228 	
8229 	      /* get and add binvars into var array */
8230 	      SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8231 	      assert(nbinvars != 0);
8232 	
8233 	      vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8234 	      assert(vals != NULL);
8235 	
8236 	      lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8237 	      ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8238 	
8239 	      /* compute start and finishing time */
8240 	      start = time - consdata->durations[idx] + 1;
8241 	      end =  MIN(time, ub);
8242 	
8243 	      /* add all neccessary binary variables */
8244 	      for( b = 0; b < nbinvars; ++b )
8245 	      {
8246 	         if( vals[b] < start || vals[b] < lb )
8247 	            continue;
8248 	
8249 	         if( vals[b] > end )
8250 	            break;
8251 	
8252 	         assert(binvars[b] != NULL);
8253 	         SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8254 	      }
8255 	   }
8256 	
8257 	   /* insert and release row */
8258 	   SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8259 	
8260 	   if( consdata->bcoverrowssize == 0 )
8261 	   {
8262 	      consdata->bcoverrowssize = 10;
8263 	      SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8264 	   }
8265 	   if( consdata->nbcoverrows == consdata->bcoverrowssize )
8266 	   {
8267 	      consdata->bcoverrowssize *= 2;
8268 	      SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8269 	   }
8270 	
8271 	   consdata->bcoverrows[consdata->nbcoverrows] = row;
8272 	   consdata->nbcoverrows++;
8273 	
8274 	   /*
8275 	    * version 2:
8276 	    * D_j := sum_i=j,...,0  d_i, finde j minimal, so dass D_j <= remainingcap
8277 	    * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8278 	    */
8279 	   /* find maximum number of jobs that can run in parallel (= coversize -1) */
8280 	   sumdemand = 0;
8281 	   j = nflexible -1;
8282 	   while( sumdemand <= remainingcap )
8283 	   {
8284 	      assert(j >= 0);
8285 	      sumdemand += demands[j];
8286 	      j--;
8287 	   }
8288 	
8289 	   smallcoversize = nflexible - (j + 1) - 1;
8290 	   while( j > 0 && demands[j] == demands[nflexible-1] )
8291 	      --j;
8292 	
8293 	   assert(smallcoversize < nflexible);
8294 	
8295 	   if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8296 	   {
8297 	      /* construct row name */
8298 	      (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8299 	      SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8300 	            SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8301 	      SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8302 	
8303 	      /* filter binary variables for each unfixed job */
8304 	      for( j = j + 1; j < nflexible; ++j )
8305 	      {
8306 	         SCIP_VAR** binvars;
8307 	         SCIP_Real* vals;
8308 	         int nbinvars;
8309 	         int idx;
8310 	         int start;
8311 	         int end;
8312 	         int lb;
8313 	         int ub;
8314 	         int b;
8315 	
8316 	         idx = flexibleids[j];
8317 	
8318 	         /* get and add binvars into var array */
8319 	         SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8320 	         assert(nbinvars != 0);
8321 	
8322 	         vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8323 	         assert(vals != NULL);
8324 	
8325 	         lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8326 	         ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8327 	
8328 	         /* compute start and finishing time */
8329 	         start = time - consdata->durations[idx] + 1;
8330 	         end =  MIN(time, ub);
8331 	
8332 	         /* add all neccessary binary variables */
8333 	         for( b = 0; b < nbinvars; ++b )
8334 	         {
8335 	            if( vals[b] < start || vals[b] < lb )
8336 	               continue;
8337 	
8338 	            if( vals[b] > end )
8339 	               break;
8340 	
8341 	            assert(binvars[b] != NULL);
8342 	            SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8343 	         }
8344 	      }
8345 	
8346 	      /* insert and release row */
8347 	      SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8348 	      if( consdata->scoverrowssize == 0 )
8349 	      {
8350 	         consdata->scoverrowssize = 10;
8351 	         SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8352 	      }
8353 	      if( consdata->nscoverrows == consdata->scoverrowssize )
8354 	      {
8355 	         consdata->scoverrowssize *= 2;
8356 	         SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8357 	      }
8358 	
8359 	      consdata->scoverrows[consdata->nscoverrows] = row;
8360 	      consdata->nscoverrows++;
8361 	   }
8362 	
8363 	   /* free buffer arrays */
8364 	   SCIPfreeBufferArray(scip, &flexibleids);
8365 	   SCIPfreeBufferArray(scip, &demands);
8366 	
8367 	   return SCIP_OKAY;
8368 	}
8369 	
8370 	/** method to construct cover cuts for all points in time */
8371 	static
8372 	SCIP_RETCODE createCoverCuts(
8373 	   SCIP*                 scip,               /**< SCIP data structure */
8374 	   SCIP_CONS*            cons                /**< constraint to be separated */
8375 	   )
8376 	{
8377 	   SCIP_CONSDATA* consdata;
8378 	
8379 	   int* startvalues;        /* stores when each job is starting */
8380 	   int* endvalues;          /* stores when each job ends */
8381 	   int* startvaluessorted;  /* stores when each job is starting */
8382 	   int* endvaluessorted;    /* stores when each job ends */
8383 	   int* startindices;     /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8384 	   int* endindices;       /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8385 	
8386 	   int nvars;               /* number of jobs for this constraint */
8387 	   int freecapacity;        /* remaining capacity */
8388 	   int curtime;             /* point in time which we are just checking */
8389 	   int endidx;              /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8390 	
8391 	   int hmin;
8392 	   int hmax;
8393 	
8394 	   int j;
8395 	   int t;
8396 	
8397 	   assert(scip != NULL);
8398 	   assert(cons != NULL);
8399 	
8400 	   consdata = SCIPconsGetData(cons);
8401 	   assert(consdata != NULL);
8402 	
8403 	   /* if no activities are associated with this resource then this constraint is redundant */
8404 	   if( consdata->vars == NULL )
8405 	      return SCIP_OKAY;
8406 	
8407 	   nvars = consdata->nvars;
8408 	   hmin = consdata->hmin;
8409 	   hmax = consdata->hmax;
8410 	
8411 	   SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8412 	   SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8413 	   SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8414 	   SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8415 	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8416 	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8417 	
8418 	   /* assign start and endpoints to arrays */
8419 	   for ( j = 0; j < nvars; ++j )
8420 	   {
8421 	      startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8422 	      startvaluessorted[j] = startvalues[j];
8423 	
8424 	      endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8425 	      endvaluessorted[j] = endvalues[j];
8426 	
8427 	      startindices[j] = j;
8428 	      endindices[j] = j;
8429 	   }
8430 	
8431 	   /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8432 	    * (and sort the indices in the same way) */
8433 	   SCIPsortIntInt(startvaluessorted, startindices, nvars);
8434 	   SCIPsortIntInt(endvaluessorted, endindices, nvars);
8435 	
8436 	   endidx = 0;
8437 	   freecapacity = consdata->capacity;
8438 	
8439 	   /* check each startpoint of a job whether the capacity is kept or not */
8440 	   for( j = 0; j < nvars; ++j )
8441 	   {
8442 	      curtime = startvaluessorted[j];
8443 	      if( curtime >= hmax )
8444 	         break;
8445 	
8446 	      /* subtract all capacity needed up to this point */
8447 	      freecapacity -= consdata->demands[startindices[j]];
8448 	
8449 	      while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8450 	      {
8451 	         ++j;
8452 	         freecapacity -= consdata->demands[startindices[j]];
8453 	      }
8454 	
8455 	      /* free all capacity usages of jobs the are no longer running */
8456 	      while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8457 	      {
8458 	         freecapacity += consdata->demands[endindices[endidx]];
8459 	         ++endidx;
8460 	      }
8461 	
8462 	      assert(freecapacity <= consdata->capacity);
8463 	      assert(endidx <= nvars);
8464 	
8465 	      /* --> endindex - points to the next job which will finish
8466 	       *     j        - points to the last job that has been released
8467 	       */
8468 	
8469 	      /* check freecapacity to be smaller than zero
8470 	       * then we will add cover constraints to the MIP
8471 	       */
8472 	      if( freecapacity < 0 && curtime >= hmin )
8473 	      {
8474 	         int nextprofilechange;
8475 	
8476 	         /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8477 	         if( j < nvars-1 )
8478 	            nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8479 	         else
8480 	            nextprofilechange = endvaluessorted[endidx];
8481 	
8482 	         nextprofilechange = MIN(nextprofilechange, hmax);
8483 	
8484 	         for( t = curtime; t < nextprofilechange; ++t )
8485 	         {
8486 	            SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8487 	
8488 	            /* create covering constraint */
8489 	            SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t)  );
8490 	         }
8491 	      } /* end if freecapacity > 0 */
8492 	   } /*lint --e{850}*/
8493 	
8494 	   consdata->covercuts = TRUE;
8495 	
8496 	   /* free all buffer arrays */
8497 	   SCIPfreeBufferArray(scip, &endindices);
8498 	   SCIPfreeBufferArray(scip, &startindices);
8499 	   SCIPfreeBufferArray(scip, &endvaluessorted);
8500 	   SCIPfreeBufferArray(scip, &startvaluessorted);
8501 	   SCIPfreeBufferArray(scip, &endvalues);
8502 	   SCIPfreeBufferArray(scip, &startvalues);
8503 	
8504 	   return SCIP_OKAY;
8505 	}
8506 	
8507 	/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8508 	 *  constraint
8509 	 */
8510 	static
8511 	SCIP_RETCODE createCapacityRestriction(
8512 	   SCIP*                 scip,               /**< SCIP data structure */
8513 	   SCIP_CONS*            cons,               /**< constraint to be checked */
8514 	   int*                  startindices,       /**< permutation with rspect to the start times */
8515 	   int                   curtime,            /**< current point in time */
8516 	   int                   nstarted,           /**< number of jobs that start before the curtime or at curtime */
8517 	   int                   nfinished,          /**< number of jobs that finished before curtime or at curtime */
8518 	   SCIP_Bool             cutsasconss         /**< should the cumulative constraint create the cuts as constraints? */
8519 	   )
8520 	{
8521 	   SCIP_CONSDATA* consdata;
8522 	   SCIP_VAR** binvars;
8523 	   int* coefs;
8524 	   int nbinvars;
8525 	   char name[SCIP_MAXSTRLEN];
8526 	   int capacity;
8527 	   int b;
8528 	
8529 	   assert(nstarted > nfinished);
8530 	
8531 	   consdata = SCIPconsGetData(cons);
8532 	   assert(consdata != NULL);
8533 	   assert(consdata->nvars > 0);
8534 	
8535 	   capacity = consdata->capacity;
8536 	   assert(capacity > 0);
8537 	
8538 	   nbinvars = 0;
8539 	   SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8540 	
8541 	   /* construct row name */
8542 	   (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8543 	
8544 	   if( cutsasconss )
8545 	   {
8546 	      SCIP_CONS* lincons;
8547 	
8548 	      /* create knapsack constraint for the given time point */
8549 	      SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8550 	            TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8551 	
8552 	      for( b = 0; b < nbinvars; ++b )
8553 	      {
8554 	         SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8555 	      }
8556 	
8557 	      /* add and release the new constraint */
8558 	      SCIP_CALL( SCIPaddCons(scip, lincons) );
8559 	      SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8560 	   }
8561 	   else
8562 	   {
8563 	      SCIP_ROW* row;
8564 	
8565 	      SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8566 	      SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8567 	
8568 	      for( b = 0; b < nbinvars; ++b )
8569 	      {
8570 	         SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8571 	      }
8572 	
8573 	      SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8574 	      SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8575 	
8576 	      if( consdata->demandrowssize == 0 )
8577 	      {
8578 	         consdata->demandrowssize = 10;
8579 	         SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8580 	      }
8581 	      if( consdata->ndemandrows == consdata->demandrowssize )
8582 	      {
8583 	         consdata->demandrowssize *= 2;
8584 	         SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8585 	      }
8586 	
8587 	      consdata->demandrows[consdata->ndemandrows] = row;
8588 	      consdata->ndemandrows++;
8589 	   }
8590 	
8591 	   SCIPfreeBufferArrayNull(scip, &binvars);
8592 	   SCIPfreeBufferArrayNull(scip, &coefs);
8593 	
8594 	   return SCIP_OKAY;
8595 	}
8596 	
8597 	/** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8598 	 *  row
8599 	 */
8600 	static
8601 	SCIP_RETCODE consCapacityConstraintsFinder(
8602 	   SCIP*                 scip,               /**< SCIP data structure */
8603 	   SCIP_CONS*            cons,               /**< constraint to be checked */
8604 	   SCIP_Bool             cutsasconss         /**< should the cumulative constraint create the cuts as constraints? */
8605 	   )
8606 	{
8607 	   SCIP_CONSDATA* consdata;
8608 	
8609 	   int* starttimes;         /* stores when each job is starting */
8610 	   int* endtimes;           /* stores when each job ends */
8611 	   int* startindices;       /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8612 	   int* endindices;         /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8613 	
8614 	   int nvars;               /* number of activities for this constraint */
8615 	   int freecapacity;        /* remaining capacity */
8616 	   int curtime;             /* point in time which we are just checking */
8617 	   int endindex;            /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8618 	
8619 	   int hmin;
8620 	   int hmax;
8621 	
8622 	   int j;
8623 	
8624 	   assert(scip != NULL);
8625 	   assert(cons != NULL);
8626 	
8627 	   consdata = SCIPconsGetData(cons);
8628 	   assert(consdata != NULL);
8629 	
8630 	   nvars = consdata->nvars;
8631 	
8632 	   /* if no activities are associated with this cumulative then this constraint is redundant */
8633 	   if( nvars == 0 )
8634 	      return SCIP_OKAY;
8635 	
8636 	   assert(consdata->vars != NULL);
8637 	
8638 	   SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8639 	   SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8640 	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8641 	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8642 	
8643 	   SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8644 	      SCIPconsGetName(cons), nvars);
8645 	
8646 	   /* create event point arrays */
8647 	   createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8648 	      starttimes, endtimes, startindices, endindices, FALSE);
8649 	
8650 	   endindex = 0;
8651 	   freecapacity = consdata->capacity;
8652 	   hmin = consdata->hmin;
8653 	   hmax = consdata->hmax;
8654 	
8655 	   /* check each startpoint of a job whether the capacity is kept or not */
8656 	   for( j = 0; j < nvars; ++j )
8657 	   {
8658 	      curtime = starttimes[j];
8659 	      SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8660 	
8661 	      if( curtime >= hmax )
8662 	         break;
8663 	
8664 	      /* remove the capacity requirments for all job which start at the curtime */
8665 	      subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8666 	
8667 	      /* add the capacity requirments for all job which end at the curtime */
8668 	      addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8669 	
8670 	      assert(freecapacity <= consdata->capacity);
8671 	      assert(endindex <= nvars);
8672 	
8673 	      /* endindex - points to the next job which will finish */
8674 	      /* j - points to the last job that has been released */
8675 	
8676 	      /* if free capacity is smaller than zero, then add rows to the LP */
8677 	      if( freecapacity < 0 && curtime >= hmin )
8678 	      {
8679 	         int nextstarttime;
8680 	         int t;
8681 	
8682 	         /* step forward until next job is released and see whether capacity constraint is met or not */
8683 	         if( j < nvars-1 )
8684 	            nextstarttime = starttimes[j+1];
8685 	         else
8686 	            nextstarttime = endtimes[nvars-1];
8687 	
8688 	         nextstarttime = MIN(nextstarttime, hmax);
8689 	
8690 	         /* create capacity restriction row for current event point */
8691 	         SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8692 	
8693 	         /* create for all points in time between the current event point and next start event point a row if the free
8694 	          * capacity is still smaller than zero  */
8695 	         for( t = curtime+1 ; t < nextstarttime; ++t )
8696 	         {
8697 	            /* add the capacity requirments for all job which end at the curtime */
8698 	            addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8699 	
8700 	            if( freecapacity < 0 )
8701 	            {
8702 	               /* add constraint */
8703 	               SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8704 	
8705 	               /* create capacity restriction row */
8706 	               SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8707 	            }
8708 	            else
8709 	               break;
8710 	         }
8711 	      }
8712 	   } /*lint --e{850}*/
8713 	
8714 	   /* free all buffer arrays */
8715 	   SCIPfreeBufferArray(scip, &endindices);
8716 	   SCIPfreeBufferArray(scip, &startindices);
8717 	   SCIPfreeBufferArray(scip, &endtimes);
8718 	   SCIPfreeBufferArray(scip, &starttimes);
8719 	
8720 	   return SCIP_OKAY;
8721 	}
8722 	
8723 	/** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8724 	 *  capacity is larger than the capacity of the cumulative constraint
8725 	 *  - for each necessary point in time:
8726 	 *
8727 	 *    sum_j sum_t demand_j * x_{j,t} <= capacity
8728 	 *
8729 	 *    where x(j,t) is the binary variables of job j at time t
8730 	 */
8731 	static
8732 	SCIP_RETCODE createRelaxation(
8733 	   SCIP*                 scip,               /**< SCIP data structure */
8734 	   SCIP_CONS*            cons,               /**< cumulative constraint */
8735 	   SCIP_Bool             cutsasconss         /**< should the cumulative constraint create the cuts as constraints? */
8736 	   )
8737 	{
8738 	   SCIP_CONSDATA* consdata;
8739 	
8740 	   consdata = SCIPconsGetData(cons);
8741 	   assert(consdata != NULL);
8742 	   assert(consdata->demandrows == NULL);
8743 	   assert(consdata->ndemandrows == 0);
8744 	
8745 	   /* collect the linking constraints */
8746 	   if( consdata->linkingconss == NULL )
8747 	   {
8748 	      SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8749 	   }
8750 	
8751 	   SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8752 	
8753 	   /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8754 	   if( cutsasconss )
8755 	   {
8756 	      if( SCIPconsIsInitial(cons) )
8757 	      {
8758 	         SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8759 	      }
8760 	      if( SCIPconsIsSeparated(cons) )
8761 	      {
8762 	         SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8763 	      }
8764 	      if( SCIPconsIsEnforced(cons) )
8765 	      {
8766 	         SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8767 	      }
8768 	   }
8769 	
8770 	   return SCIP_OKAY;
8771 	}
8772 	
8773 	/** adds linear relaxation of cumulative constraint to the LP */
8774 	static
8775 	SCIP_RETCODE addRelaxation(
8776 	   SCIP*                 scip,               /**< SCIP data structure */
8777 	   SCIP_CONS*            cons,               /**< cumulative constraint */
8778 	   SCIP_Bool             cutsasconss,        /**< should the cumulative constraint create the cuts as constraints? */
8779 	   SCIP_Bool*            infeasible          /**< pointer to store whether an infeasibility was detected */
8780 	   )
8781 	{
8782 	   SCIP_CONSDATA* consdata;
8783 	   int r;
8784 	
8785 	   consdata = SCIPconsGetData(cons);
8786 	   assert(consdata != NULL);
8787 	
8788 	   if( consdata->demandrows == NULL )
8789 	   {
8790 	      assert(consdata->ndemandrows == 0);
8791 	
8792 	      SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8793 	
8794 	      return SCIP_OKAY;
8795 	   }
8796 	
8797 	   for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8798 	   {
8799 	      if( !SCIProwIsInLP(consdata->demandrows[r]) )
8800 	      {
8801 	         assert(consdata->demandrows[r] != NULL);
8802 	         SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8803 	      }
8804 	   }
8805 	
8806 	   return SCIP_OKAY;
8807 	}
8808 	
8809 	/** checks constraint for violation, and adds it as a cut if possible */
8810 	static
8811 	SCIP_RETCODE separateConsBinaryRepresentation(
8812 	   SCIP*                 scip,               /**< SCIP data structure */
8813 	   SCIP_CONS*            cons,               /**< cumulative constraint to be separated */
8814 	   SCIP_SOL*             sol,                /**< primal CIP solution, NULL for current LP solution */
8815 	   SCIP_Bool*            separated,          /**< pointer to store TRUE, if a cut was found */
8816 	   SCIP_Bool*            cutoff              /**< whether a cutoff has been detected */
8817 	   )
8818 	{  /*lint --e{715}*/
8819 	   SCIP_CONSDATA* consdata;
8820 	   int ncuts;
8821 	   int r;
8822 	
8823 	   assert(scip != NULL);
8824 	   assert(cons != NULL);
8825 	   assert(separated != NULL);
8826 	   assert(cutoff != NULL);
8827 	
8828 	   *separated = FALSE;
8829 	   *cutoff = FALSE;
8830 	
8831 	   consdata = SCIPconsGetData(cons);
8832 	   assert(consdata != NULL);
8833 	
8834 	   SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8835 	
8836 	   if( consdata->demandrows == NULL )
8837 	   {
8838 	      assert(consdata->ndemandrows == 0);
8839 	
8840 	      SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8841 	
8842 	      return SCIP_OKAY;
8843 	   }
8844 	
8845 	   ncuts = 0;
8846 	
8847 	   /* check each row that is not contained in LP */
8848 	   for( r = 0; r < consdata->ndemandrows; ++r )
8849 	   {
8850 	      if( !SCIProwIsInLP(consdata->demandrows[r]) )
8851 	      {
8852 	         SCIP_Real feasibility;
8853 	
8854 	         if( sol != NULL )
8855 	            feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8856 	         else
8857 	            feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8858 	
8859 	         if( SCIPisFeasNegative(scip, feasibility) )
8860 	         {
8861 	            SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8862 	            if ( *cutoff )
8863 	            {
8864 	               SCIP_CALL( SCIPresetConsAge(scip, cons) );
8865 	               return SCIP_OKAY;
8866 	            }
8867 	            *separated = TRUE;
8868 	            ncuts++;
8869 	         }
8870 	      }
8871 	   }
8872 	
8873 	   if( ncuts > 0 )
8874 	   {
8875 	      SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n",  SCIPconsGetName(cons), ncuts);
8876 	
8877 	      /* if successful, reset age of constraint */
8878 	      SCIP_CALL( SCIPresetConsAge(scip, cons) );
8879 	      (*separated) = TRUE;
8880 	   }
8881 	
8882 	   return SCIP_OKAY;
8883 	}
8884 	
8885 	/** checks constraint for violation, and adds it as a cut if possible */
8886 	static
8887 	SCIP_RETCODE separateCoverCutsCons(
8888 	   SCIP*                 scip,               /**< SCIP data structure */
8889 	   SCIP_CONS*            cons,               /**< logic or constraint to be separated */
8890 	   SCIP_SOL*             sol,                /**< primal CIP solution, NULL for current LP solution */
8891 	   SCIP_Bool*            separated,          /**< pointer to store TRUE, if a cut was found */
8892 	   SCIP_Bool*            cutoff              /**< whether a cutoff has been detected */
8893 	   )
8894 	{
8895 	   SCIP_CONSDATA* consdata;
8896 	   SCIP_ROW* row;
8897 	   SCIP_Real minfeasibility;
8898 	   int r;
8899 	
8900 	   assert(scip != NULL);
8901 	   assert(cons != NULL);
8902 	   assert(separated != NULL);
8903 	   assert(cutoff != NULL);
8904 	
8905 	   *separated = FALSE;
8906 	   *cutoff = FALSE;
8907 	
8908 	   consdata = SCIPconsGetData(cons);
8909 	   assert(consdata != NULL);
8910 	
8911 	   SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8912 	
8913 	   /* collect the linking constraints */
8914 	   if( consdata->linkingconss == NULL )
8915 	   {
8916 	      SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8917 	   }
8918 	
8919 	   if( !consdata->covercuts )
8920 	   {
8921 	      SCIP_CALL( createCoverCuts(scip, cons) );
8922 	   }
8923 	
8924 	   row = NULL;
8925 	   minfeasibility = SCIPinfinity(scip);
8926 	
8927 	   /* check each row of small covers that is not contained in LP */
8928 	   for( r = 0; r < consdata->nscoverrows; ++r )
8929 	   {
8930 	      if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8931 	      {
8932 	         SCIP_Real feasibility;
8933 	
8934 	         assert(consdata->scoverrows[r] != NULL);
8935 	         if( sol != NULL )
8936 	            feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8937 	         else
8938 	            feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8939 	
8940 	         if( minfeasibility > feasibility )
8941 	         {
8942 	            minfeasibility = feasibility;
8943 	            row =  consdata->scoverrows[r];
8944 	         }
8945 	      }
8946 	   }
8947 	
8948 	   assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8949 	
8950 	   if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8951 	   {
8952 	      SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8953 	         SCIPconsGetName(cons), minfeasibility);
8954 	
8955 	      SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8956 	      SCIP_CALL( SCIPresetConsAge(scip, cons) );
8957 	      if ( *cutoff )
8958 	         return SCIP_OKAY;
8959 	      (*separated) = TRUE;
8960 	   }
8961 	
8962 	   minfeasibility = SCIPinfinity(scip);
8963 	   row = NULL;
8964 	
8965 	   /* check each row of small covers that is not contained in LP */
8966 	   for( r = 0; r < consdata->nbcoverrows; ++r )
8967 	   {
8968 	      if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8969 	      {
8970 	         SCIP_Real feasibility;
8971 	
8972 	         assert(consdata->bcoverrows[r] != NULL);
8973 	         if( sol != NULL )
8974 	            feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8975 	         else
8976 	            feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8977 	
8978 	         if( minfeasibility > feasibility )
8979 	         {
8980 	            minfeasibility = feasibility;
8981 	            row =  consdata->bcoverrows[r];
8982 	         }
8983 	      }
8984 	   }
8985 	
8986 	   assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8987 	
8988 	   if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8989 	   {
8990 	      SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8991 	         SCIPconsGetName(cons), minfeasibility);
8992 	
8993 	      assert(row != NULL);
8994 	      SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8995 	      SCIP_CALL( SCIPresetConsAge(scip, cons) );
8996 	      if ( *cutoff )
8997 	         return SCIP_OKAY;
8998 	      (*separated) = TRUE;
8999 	   }
9000 	
9001 	   return SCIP_OKAY;
9002 	}
9003 	
9004 	/** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
9005 	static
9006 	SCIP_RETCODE createCapacityRestrictionIntvars(
9007 	   SCIP*                 scip,               /**< SCIP data structure */
9008 	   SCIP_CONS*            cons,               /**< constraint to be checked */
9009 	   int*                  startindices,       /**< permutation with rspect to the start times */
9010 	   int                   curtime,            /**< current point in time */
9011 	   int                   nstarted,           /**< number of jobs that start before the curtime or at curtime */
9012 	   int                   nfinished,          /**< number of jobs that finished before curtime or at curtime */
9013 	   SCIP_Bool             lower,              /**< shall cuts be created due to lower or upper bounds? */
9014 	   SCIP_Bool*            cutoff              /**< pointer to store TRUE, if a cutoff was detected */
9015 	   )
9016 	{
9017 	   SCIP_CONSDATA* consdata;
9018 	   char name[SCIP_MAXSTRLEN];
9019 	   int lhs; /* left hand side of constraint */
9020 	
9021 	   SCIP_VAR** activevars;
9022 	   SCIP_ROW* row;
9023 	
9024 	   int v;
9025 	
9026 	   assert(nstarted > nfinished);
9027 	
9028 	   consdata = SCIPconsGetData(cons);
9029 	   assert(consdata != NULL);
9030 	   assert(consdata->nvars > 0);
9031 	
9032 	   SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
9033 	
9034 	   SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
9035 	
9036 	   if( lower )
9037 	   {
9038 	      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
9039 	
9040 	      SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
9041 	            TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9042 	   }
9043 	   else
9044 	   {
9045 	      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
9046 	      SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
9047 	            TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9048 	   }
9049 	
9050 	   SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
9051 	
9052 	   for( v = 0; v < nstarted - nfinished; ++v )
9053 	   {
9054 	      SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9055 	   }
9056 	
9057 	   SCIP_CALL( SCIPflushRowExtensions(scip, row) );
9058 	   SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9059 	
9060 	   SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9061 	
9062 	   SCIP_CALL( SCIPreleaseRow(scip, &row) );
9063 	
9064 	   /* free buffers */
9065 	   SCIPfreeBufferArrayNull(scip, &activevars);
9066 	
9067 	   return SCIP_OKAY;
9068 	}
9069 	
9070 	/** checks constraint for violation, and adds it as a cut if possible */
9071 	static
9072 	SCIP_RETCODE separateConsOnIntegerVariables(
9073 	   SCIP*                 scip,               /**< SCIP data structure */
9074 	   SCIP_CONS*            cons,               /**< cumulative constraint to be separated */
9075 	   SCIP_SOL*             sol,                /**< primal CIP solution, NULL for current LP solution */
9076 	   SCIP_Bool             lower,              /**< shall cuts be created according to lower bounds? */
9077 	   SCIP_Bool*            separated,          /**< pointer to store TRUE, if a cut was found */
9078 	   SCIP_Bool*            cutoff              /**< pointer to store TRUE, if a cutoff was detected */
9079 	   )
9080 	{
9081 	   SCIP_CONSDATA* consdata;
9082 	
9083 	   int* starttimes;         /* stores when each job is starting */
9084 	   int* endtimes;           /* stores when each job ends */
9085 	   int* startindices;       /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9086 	   int* endindices;         /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9087 	
9088 	   int nvars;               /* number of activities for this constraint */
9089 	   int freecapacity;        /* remaining capacity */
9090 	   int curtime;             /* point in time which we are just checking */
9091 	   int endindex;            /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9092 	
9093 	   int hmin;
9094 	   int hmax;
9095 	   int j;
9096 	
9097 	   assert(scip != NULL);
9098 	   assert(cons != NULL);
9099 	
9100 	   consdata = SCIPconsGetData(cons);
9101 	   assert(consdata != NULL);
9102 	
9103 	   nvars = consdata->nvars;
9104 	
9105 	   /* if no activities are associated with this cumulative then this constraint is redundant */
9106 	   if( nvars <= 1 )
9107 	      return SCIP_OKAY;
9108 	
9109 	   assert(consdata->vars != NULL);
9110 	
9111 	   SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9112 	   SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9113 	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9114 	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9115 	
9116 	   SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9117 	      SCIPconsGetName(cons), nvars);
9118 	
9119 	   /* create event point arrays */
9120 	   createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9121 	
9122 	   /* now nvars might be smaller than before! */
9123 	
9124 	   endindex = 0;
9125 	   freecapacity = consdata->capacity;
9126 	   hmin = consdata->hmin;
9127 	   hmax = consdata->hmax;
9128 	
9129 	   /* check each startpoint of a job whether the capacity is kept or not */
9130 	   for( j = 0; j < nvars && !(*cutoff); ++j )
9131 	   {
9132 	      curtime = starttimes[j];
9133 	
9134 	      if( curtime >= hmax )
9135 	         break;
9136 	
9137 	      /* remove the capacity requirements for all job which start at the curtime */
9138 	      subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9139 	
9140 	      /* add the capacity requirments for all job which end at the curtime */
9141 	      addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9142 	
9143 	      assert(freecapacity <= consdata->capacity);
9144 	      assert(endindex <= nvars);
9145 	
9146 	      /* endindex - points to the next job which will finish */
9147 	      /* j - points to the last job that has been released */
9148 	
9149 	      /* if free capacity is smaller than zero, then add rows to the LP */
9150 	      if( freecapacity < 0 && curtime >= hmin)
9151 	      {
9152 	         /* create capacity restriction row for current event point */
9153 	         SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9154 	         *separated = TRUE;
9155 	      }
9156 	   } /*lint --e{850}*/
9157 	
9158 	   /* free all buffer arrays */
9159 	   SCIPfreeBufferArray(scip, &endindices);
9160 	   SCIPfreeBufferArray(scip, &startindices);
9161 	   SCIPfreeBufferArray(scip, &endtimes);
9162 	   SCIPfreeBufferArray(scip, &starttimes);
9163 	
9164 	   return SCIP_OKAY;
9165 	}
9166 	
9167 	/**@} */
9168 	
9169 	
9170 	/**@name Presolving
9171 	 *
9172 	 * @{
9173 	 */
9174 	
9175 	#ifndef NDEBUG
9176 	/** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9177 	 *  correct
9178 	 */
9179 	static
9180 	SCIP_Bool checkDemands(
9181 	   SCIP*                 scip,               /**< SCIP data structure */
9182 	   SCIP_CONS*            cons                /**< constraint to be checked */
9183 	   )
9184 	{
9185 	   SCIP_CONSDATA* consdata;
9186 	   int capacity;
9187 	   int nvars;
9188 	   int j;
9189 	
9190 	   assert(scip != NULL);
9191 	   assert(cons != NULL);
9192 	
9193 	   consdata = SCIPconsGetData(cons);
9194 	   assert(consdata != NULL);
9195 	
9196 	   nvars = consdata->nvars;
9197 	
9198 	   /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9199 	   if( nvars <= 1 )
9200 	      return TRUE;
9201 	
9202 	   assert(consdata->vars != NULL);
9203 	   capacity = consdata->capacity;
9204 	
9205 	   /* check each activity: if demand is larger than capacity the problem is infeasible */
9206 	   for ( j = 0; j < nvars; ++j )
9207 	   {
9208 	      if( consdata->demands[j] > capacity )
9209 	         return FALSE;
9210 	   }
9211 	
9212 	   return TRUE;
9213 	}
9214 	#endif
9215 	
9216 	/** delete constraint if it consists of at most one job
9217 	 *
9218 	 *  @todo this method needs to be adjusted w.r.t. effective horizon
9219 	 */
9220 	static
9221 	SCIP_RETCODE deleteTrivilCons(
9222 	   SCIP*                 scip,               /**< SCIP data structure */
9223 	   SCIP_CONS*            cons,               /**< constraint to propagate */
9224 	   int*                  ndelconss,          /**< pointer to store the number of deleted constraints */
9225 	   SCIP_Bool*            cutoff              /**< pointer to store if the constraint is infeasible */
9226 	   )
9227 	{
9228 	   SCIP_CONSDATA* consdata;
9229 	
9230 	   assert(scip != NULL);
9231 	   assert(cons != NULL);
9232 	
9233 	   consdata = SCIPconsGetData(cons);
9234 	   assert(consdata != NULL);
9235 	
9236 	   if( consdata->nvars == 0 )
9237 	   {
9238 	      SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9239 	
9240 	      SCIP_CALL( SCIPdelCons(scip, cons) );
9241 	      (*ndelconss)++;
9242 	   }
9243 	   else if( consdata->nvars == 1 )
9244 	   {
9245 	      if( consdata->demands[0] > consdata->capacity )
9246 	         (*cutoff) = TRUE;
9247 	      else
9248 	      {
9249 	         SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9250 	
9251 	         SCIP_CALL( SCIPdelCons(scip, cons) );
9252 	         (*ndelconss)++;
9253 	      }
9254 	   }
9255 	
9256 	   return SCIP_OKAY;
9257 	}
9258 	
9259 	/** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9260 	 *  this is done in the SCIP_DECL_CONSINITPRE() callback
9261 	 */
9262 	static
9263 	SCIP_RETCODE removeIrrelevantJobs(
9264 	   SCIP*                 scip,               /**< SCIP data structure */
9265 	   SCIP_CONS*            cons                /**< constraint to propagate */
9266 	   )
9267 	{
9268 	   SCIP_CONSDATA* consdata;
9269 	   SCIP_VAR* var;
9270 	   int demand;
9271 	   int duration;
9272 	   int hmin;
9273 	   int hmax;
9274 	   int est;
9275 	   int lct;
9276 	   int j;
9277 	
9278 	   assert(scip != NULL);
9279 	   assert(cons != NULL);
9280 	
9281 	   consdata = SCIPconsGetData(cons);
9282 	   assert(consdata != NULL);
9283 	
9284 	   hmin = consdata->hmin;
9285 	   hmax = consdata->hmax;
9286 	
9287 	   SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9288 	      SCIPconsGetName(cons), hmin, hmax);
9289 	
9290 	   for( j = consdata->nvars-1; j >= 0; --j )
9291 	   {
9292 	      var = consdata->vars[j];
9293 	      demand = consdata->demands[j];
9294 	      duration = consdata->durations[j];
9295 	
9296 	      /* earliest completion time (ect) and latest start time (lst) */
9297 	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9298 	      lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9299 	
9300 	      if( demand == 0 || duration == 0 )
9301 	      {
9302 	         /* jobs with zero demand or zero duration can be removed */
9303 	         SCIPdebugMsg(scip, "  remove variable <%s> due to zero %s\n",
9304 	            SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9305 	
9306 	         /* remove variable form constraint */
9307 	         SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9308 	      }
9309 	      else if( est >= hmax || lct <= hmin )
9310 	      {
9311 	         SCIPdebugMsg(scip, "  remove variable <%s>[%d,%d] with duration <%d>\n",
9312 	            SCIPvarGetName(var), est, lct - duration, duration);
9313 	
9314 	         /* delete variable at the given position */
9315 	         SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9316 	
9317 	         /* for the statistic we count the number of jobs which are irrelevant */
9318 	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9319 	      }
9320 	   }
9321 	
9322 	   return SCIP_OKAY;
9323 	}
9324 	
9325 	/** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9326 	static
9327 	SCIP_RETCODE adjustOversizedJobBounds(
9328 	   SCIP*                 scip,               /**< SCIP data structure */
9329 	   SCIP_CONSDATA*        consdata,           /**< constraint data */
9330 	   int                   pos,                /**< position of job in the consdata */
9331 	   int*                  nchgbds,            /**< pointer to store the number of changed bounds */
9332 	   int*                  naddconss,          /**< pointer to store the number of added constraints */
9333 	   SCIP_Bool*            cutoff              /**< pointer to store if a cutoff was detected */
9334 	   )
9335 	{
9336 	   SCIP_VAR* var;
9337 	   SCIP_Bool tightened;
9338 	   int duration;
9339 	   int ect;
9340 	   int lst;
9341 	
9342 	   assert(scip != NULL);
9343 	
9344 	   /* zero energy jobs should be removed already */
9345 	   assert(consdata->durations[pos] > 0);
9346 	   assert(consdata->demands[pos] > 0);
9347 	
9348 	   var = consdata->vars[pos];
9349 	   assert(var != NULL);
9350 	   duration =  consdata->durations[pos];
9351 	
9352 	   /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9353 	   SCIPdebugMsg(scip, "  variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9354 	      SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9355 	
9356 	   /* earliest completion time (ect) and latest start time (lst) */
9357 	   ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9358 	   lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9359 	
9360 	   /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9361 	   if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9362 	      return SCIP_OKAY;
9363 	
9364 	   if( ect > consdata->hmin && lst < consdata->hmax )
9365 	   {
9366 	      /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9367 	      *cutoff = TRUE;
9368 	   }
9369 	   else if( lst < consdata->hmax )
9370 	   {
9371 	      /* move the latest start time of this job in such a way that it finishes before or at hmin */
9372 	      SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9373 	      assert(tightened);
9374 	      assert(!(*cutoff));
9375 	      (*nchgbds)++;
9376 	   }
9377 	   else if( ect > consdata->hmin )
9378 	   {
9379 	      /* move the earliest start time of this job in such a way that it starts after or at hmax */
9380 	      SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9381 	      assert(tightened);
9382 	      assert(!(*cutoff));
9383 	      (*nchgbds)++;
9384 	   }
9385 	   else
9386 	   {
9387 	      /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9388 	       * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9389 	       *
9390 	       * (var <= hmin - duration) /\ (var >= hmax)
9391 	       */
9392 	      SCIP_CONS* cons;
9393 	
9394 	      SCIP_VAR* vartuple[2];
9395 	      SCIP_BOUNDTYPE boundtypetuple[2];
9396 	      SCIP_Real boundtuple[2];
9397 	
9398 	      char name[SCIP_MAXSTRLEN];
9399 	      int leftbound;
9400 	      int rightbound;
9401 	
9402 	      leftbound = consdata->hmin - duration;
9403 	      rightbound = consdata->hmax;
9404 	
9405 	      /* allocate temporary memory for arrays */
9406 	      vartuple[0] = var;
9407 	      vartuple[1] = var;
9408 	      boundtuple[0] = (SCIP_Real)leftbound;
9409 	      boundtuple[1] = (SCIP_Real)rightbound;
9410 	      boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9411 	      boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9412 	
9413 	      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9414 	         SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9415 	
9416 	      /* create and add bounddisjunction constraint */
9417 	      SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9418 	            TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9419 	
9420 	      SCIPdebugPrintCons(scip, cons, NULL);
9421 	
9422 	      /* add and release the new constraint */
9423 	      SCIP_CALL( SCIPaddCons(scip, cons) );
9424 	      SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9425 	      (*naddconss)++;
9426 	   }
9427 	
9428 	   return SCIP_OKAY;
9429 	}
9430 	
9431 	/** try to removed over sizeed jobs (the demand is larger than the capacity) */
9432 	static
9433 	SCIP_RETCODE removeOversizedJobs(
9434 	   SCIP*                 scip,               /**< SCIP data structure */
9435 	   SCIP_CONS*            cons,               /**< constraint */
9436 	   int*                  nchgbds,            /**< pointer to store the number of changed bounds */
9437 	   int*                  nchgcoefs,          /**< pointer to store the number of changed coefficient */
9438 	   int*                  naddconss,          /**< pointer to store the number of added constraints */
9439 	   SCIP_Bool*            cutoff              /**< pointer to store if a cutoff was detected */
9440 	   )
9441 	{
9442 	   SCIP_CONSDATA* consdata;
9443 	   int capacity;
9444 	   int j;
9445 	
9446 	   consdata = SCIPconsGetData(cons);
9447 	   assert(consdata != NULL);
9448 	
9449 	   /* if a cutoff was already detected just return */
9450 	   if( *cutoff )
9451 	      return SCIP_OKAY;
9452 	
9453 	   capacity = consdata->capacity;
9454 	
9455 	   for( j = consdata->nvars-1; j >= 0 && !(*cutoff);  --j )
9456 	   {
9457 	      if( consdata->demands[j] > capacity )
9458 	      {
9459 	         SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9460 	
9461 	         /* remove variable form constraint */
9462 	         SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9463 	         (*nchgcoefs)++;
9464 	      }
9465 	   }
9466 	
9467 	   SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9468 	
9469 	   return SCIP_OKAY;
9470 	}
9471 	
9472 	/** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9473 	static
9474 	SCIP_RETCODE fixIntegerVariableUb(
9475 	   SCIP*                 scip,               /**< SCIP data structure */
9476 	   SCIP_VAR*             var,                /**< integer variable to fix */
9477 	   SCIP_Bool             uplock,             /**< has thet start time variable a up lock */
9478 	   int*                  nfixedvars          /**< pointer to store the number fixed variables */
9479 	   )
9480 	{
9481 	   SCIP_Bool infeasible;
9482 	   SCIP_Bool tightened;
9483 	   SCIP_Bool roundable;
9484 	
9485 	   /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9486 	    * would/could end in an implication which can lead to cutoff of the/all optimal solution
9487 	    */
9488 	   if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9489 	      return SCIP_OKAY;
9490 	
9491 	   /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9492 	    * handler is the only one locking that variable up
9493 	    */
9494 	   assert(uplock == TRUE || uplock == FALSE);
9495 	   assert((int)TRUE == 1);  /*lint !e506*/
9496 	   assert((int)FALSE == 0); /*lint !e506*/
9497 	
9498 	   if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9499 	      return SCIP_OKAY;
9500 	
9501 	   SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9502 	
9503 	   /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9504 	    * (the transformed problem is always a minimization problem)
9505 	    */
9506 	   if( !roundable )
9507 	      return SCIP_OKAY;
9508 	
9509 	   SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9510 	      SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), SCIPvarGetUbLocal(var));
9511 	
9512 	   SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9513 	   assert(!infeasible);
9514 	
9515 	   if( tightened )
9516 	   {
9517 	      SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9518 	      (*nfixedvars)++;
9519 	   }
9520 	
9521 	   return SCIP_OKAY;
9522 	}
9523 	
9524 	/** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9525 	static
9526 	SCIP_RETCODE fixIntegerVariableLb(
9527 	   SCIP*                 scip,               /**< SCIP data structure */
9528 	   SCIP_VAR*             var,                /**< integer variable to fix */
9529 	   SCIP_Bool             downlock,           /**< has the variable a down lock */
9530 	   int*                  nfixedvars          /**< pointer to store the number fixed variables */
9531 	   )
9532 	{
9533 	   SCIP_Bool infeasible;
9534 	   SCIP_Bool tightened;
9535 	   SCIP_Bool roundable;
9536 	
9537 	   /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9538 	    * would/could end in an implication which can lead to cutoff of the/all optimal solution
9539 	    */
9540 	   if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9541 	      return SCIP_OKAY;
9542 	
9543 	   /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9544 	    * handler is the only one locking that variable down
9545 	    */
9546 	   assert(downlock == TRUE || downlock == FALSE);
9547 	   assert((int)TRUE == 1);  /*lint !e506*/
9548 	   assert((int)FALSE == 0); /*lint !e506*/
9549 	
9550 	   if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9551 	      return SCIP_OKAY;
9552 	
9553 	   SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9554 	
9555 	   /* is it possible, to round variable down w.r.t. objective function? */
9556 	   if( !roundable )
9557 	      return SCIP_OKAY;
9558 	
9559 	   SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9560 	   assert(!infeasible);
9561 	
9562 	   if( tightened )
9563 	   {
9564 	      SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9565 	      (*nfixedvars)++;
9566 	   }
9567 	
9568 	   return SCIP_OKAY;
9569 	}
9570 	
9571 	/** normalize cumulative condition */
9572 	static
9573 	void normalizeCumulativeCondition(
9574 	   SCIP*                 scip,               /**< SCIP data structure */
9575 	   int                   nvars,              /**< number of start time variables (activities) */
9576 	   int*                  demands,            /**< array of demands */
9577 	   int*                  capacity,           /**< pointer to store the changed cumulative capacity */
9578 	   int*                  nchgcoefs,          /**< pointer to count total number of changed coefficients */
9579 	   int*                  nchgsides           /**< pointer to count number of side changes */
9580 	   )
9581 	{  /*lint --e{715}*/
9582 	   SCIP_Longint gcd;
9583 	   int mindemand1;
9584 	   int mindemand2;
9585 	   int v;
9586 	
9587 	   if( *capacity == 1 || nvars <= 1 )
9588 	      return;
9589 	
9590 	   assert(demands[nvars-1] <= *capacity);
9591 	   assert(demands[nvars-2] <= *capacity);
9592 	
9593 	   gcd = (SCIP_Longint)demands[nvars-1];
9594 	   mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9595 	   mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9596 	
9597 	   for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9598 	   {
9599 	      assert(mindemand1 <= mindemand2);
9600 	      assert(demands[v] <= *capacity);
9601 	
9602 	      gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9603 	
9604 	      if( mindemand1 > demands[v] )
9605 	      {
9606 	         mindemand2 = mindemand1;
9607 	         mindemand1 = demands[v];
9608 	      }
9609 	      else if( mindemand2 > demands[v] )
9610 	         mindemand2 = demands[v];
9611 	   }
9612 	
9613 	   if( mindemand1 + mindemand2 > *capacity )
9614 	   {
9615 	      SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9616 	
9617 	      for( v = 0; v < nvars; ++v )
9618 	         demands[v] = 1;
9619 	
9620 	      (*capacity) = 1;
9621 	
9622 	      (*nchgcoefs) += nvars;
9623 	      (*nchgsides)++;
9624 	   }
9625 	   else if( gcd >= 2 )
9626 	   {
9627 	      SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9628 	
9629 	      for( v = 0; v < nvars; ++v )
9630 	         demands[v] /= (int) gcd;
9631 	
9632 	      (*capacity) /= (int) gcd;
9633 	
9634 	      (*nchgcoefs) += nvars;
9635 	      (*nchgsides)++;
9636 	   }
9637 	}
9638 	
9639 	/** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9640 	 *  in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9641 	 *  capacity since in that case none of the jobs can run in parallel
9642 	 */
9643 	static
9644 	void normalizeDemands(
9645 	   SCIP*                 scip,               /**< SCIP data structure */
9646 	   SCIP_CONS*            cons,               /**< cumulative constraint */
9647 	   int*                  nchgcoefs,          /**< pointer to count total number of changed coefficients */
9648 	   int*                  nchgsides           /**< pointer to count number of side changes */
9649 	   )
9650 	{
9651 	   SCIP_CONSDATA* consdata;
9652 	   int capacity;
9653 	
9654 	   assert(nchgcoefs != NULL);
9655 	   assert(nchgsides != NULL);
9656 	   assert(!SCIPconsIsModifiable(cons));
9657 	
9658 	   consdata = SCIPconsGetData(cons);
9659 	   assert(consdata != NULL);
9660 	
9661 	   if( consdata->normalized )
9662 	      return;
9663 	
9664 	   capacity = consdata->capacity;
9665 	
9666 	   /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9667 	
9668 	   normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9669 	
9670 	   consdata->normalized = TRUE;
9671 	
9672 	   if( capacity > consdata->capacity )
9673 	      consdata->varbounds = FALSE;
9674 	}
9675 	
9676 	/** computes for the given cumulative condition the effective horizon */
9677 	static
9678 	SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(
9679 	   SCIP*                 scip,               /**< SCIP data structure */
9680 	   int                   nvars,              /**< number of variables (jobs) */
9681 	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
9682 	   int*                  durations,          /**< array containing corresponding durations */
9683 	   int*                  demands,            /**< array containing corresponding demands */
9684 	   int                   capacity,           /**< available cumulative capacity */
9685 	   int*                  hmin,               /**< pointer to store the left bound of the effective horizon */
9686 	   int*                  hmax,               /**< pointer to store the right bound of the effective horizon */
9687 	   int*                  split               /**< point were the cumulative condition can be split */
9688 	   )
9689 	{
9690 	   SCIP_PROFILE* profile;
9691 	
9692 	   /* create empty resource profile with infinity resource capacity */
9693 	   SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9694 	
9695 	   /* create worst case resource profile */
9696 	   SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9697 	
9698 	   /* print resource profile in if SCIP_DEBUG is defined */
9699 	   SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9700 	
9701 	   /* computes the first time point where the resource capacity can be violated */
9702 	   (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9703 	
9704 	   /* computes the first time point where the resource capacity is satisfied for sure */
9705 	   (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9706 	
9707 	   (*split) = (*hmax);
9708 	
9709 	   if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9710 	   {
9711 	      int* timepoints;
9712 	      int* loads;
9713 	      int ntimepoints;
9714 	      int t;
9715 	
9716 	      /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9717 	       * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9718 	       * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9719 	       * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9720 	       * explain the certain "old" bound changes
9721 	       */
9722 	
9723 	      /* search for time points */
9724 	      ntimepoints = SCIPprofileGetNTimepoints(profile);
9725 	      timepoints = SCIPprofileGetTimepoints(profile);
9726 	      loads = SCIPprofileGetLoads(profile);
9727 	
9728 	      /* check if there exist a time point within the effective horizon [hmin,hmax) such that the capacity is not exceed w.r.t. worst case profile */
9729 	      for( t = 0; t < ntimepoints; ++t )
9730 	      {
9731 	         /* ignore all time points before the effective horizon */
9732 	         if( timepoints[t] <= *hmin )
9733 	            continue;
9734 	
9735 	         /* ignore all time points after the effective horizon */
9736 	         if( timepoints[t] >= *hmax )
9737 	            break;
9738 	
9739 	         /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9740 	          * can split the cumulative constraint into two cumulative constraints
9741 	          */
9742 	         if( loads[t] <= capacity )
9743 	         {
9744 	            (*split) = timepoints[t];
9745 	            break;
9746 	         }
9747 	      }
9748 	   }
9749 	
9750 	   /* free worst case profile */
9751 	   SCIPprofileFree(&profile);
9752 	
9753 	   return SCIP_OKAY;
9754 	}
9755 	
9756 	/** creates and adds a cumulative constraint */
9757 	static
9758 	SCIP_RETCODE createConsCumulative(
9759 	   SCIP*                 scip,               /**< SCIP data structure */
9760 	   const char*           name,               /**< name of constraint */
9761 	   int                   nvars,              /**< number of variables (jobs) */
9762 	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
9763 	   int*                  durations,          /**< array containing corresponding durations */
9764 	   int*                  demands,            /**< array containing corresponding demands */
9765 	   int                   capacity,           /**< available cumulative capacity */
9766 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
9767 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
9768 	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
9769 	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9770 	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
9771 	                                              *   Usually set to TRUE. */
9772 	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
9773 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9774 	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
9775 	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
9776 	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
9777 	                                              *   Usually set to TRUE. */
9778 	   SCIP_Bool             local,              /**< is constraint only valid locally?
9779 	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9780 	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
9781 	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
9782 	                                              *   adds coefficients to this constraint. */
9783 	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
9784 	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
9785 	                                              *   are seperated as constraints. */
9786 	   SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
9787 	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9788 	   SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
9789 	                                              *   if it may be moved to a more global node?
9790 	                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9791 	   )
9792 	{
9793 	   SCIP_CONS* cons;
9794 	
9795 	   /* creates cumulative constraint and adds it to problem */
9796 	   SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9797 	         initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9798 	
9799 	   /* adjust the effective time horizon of the new constraint */
9800 	   SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9801 	   SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9802 	
9803 	   /* add and release new cumulative constraint */
9804 	   SCIP_CALL( SCIPaddCons(scip, cons) );
9805 	   SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9806 	
9807 	   return SCIP_OKAY;
9808 	}
9809 	
9810 	/** computes the effective horizon and checks if the constraint can be decompsed */
9811 	static
9812 	SCIP_RETCODE computeEffectiveHorizon(
9813 	   SCIP*                 scip,               /**< SCIP data structure */
9814 	   SCIP_CONS*            cons,               /**< cumulative constraint */
9815 	   int*                  ndelconss,          /**< pointer to store the number of deleted constraints */
9816 	   int*                  naddconss,          /**< pointer to store the number of added constraints */
9817 	   int*                  nchgsides           /**< pointer to store the number of changed sides */
9818 	   )
9819 	{
9820 	   SCIP_CONSDATA* consdata;
9821 	   int hmin;
9822 	   int hmax;
9823 	   int split;
9824 	
9825 	   consdata = SCIPconsGetData(cons);
9826 	   assert(consdata != NULL);
9827 	
9828 	   if( consdata->nvars <= 1 )
9829 	      return SCIP_OKAY;
9830 	
9831 	   SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9832 	         consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9833 	
9834 	   /* check if this time point improves the effective horizon */
9835 	   if( consdata->hmin < hmin )
9836 	   {
9837 	      SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9838 	
9839 	      consdata->hmin = hmin;
9840 	      (*nchgsides)++;
9841 	   }
9842 	
9843 	   /* check if this time point improves the effective horizon */
9844 	   if( consdata->hmax > hmax )
9845 	   {
9846 	      SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax,  hmax);
9847 	      consdata->hmax = hmax;
9848 	      (*nchgsides)++;
9849 	   }
9850 	
9851 	   /* check if the constraint is redundant */
9852 	   if( consdata->hmax <= consdata->hmin )
9853 	   {
9854 	      SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9855 	         SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9856 	
9857 	      SCIP_CALL( SCIPdelCons(scip, cons) );
9858 	      (*ndelconss)++;
9859 	   }
9860 	   else if( consdata->hmin < split && split < consdata->hmax )
9861 	   {
9862 	      char name[SCIP_MAXSTRLEN];
9863 	      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9864 	
9865 	      SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9866 	         SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9867 	
9868 	      assert(split < consdata->hmax);
9869 	
9870 	      /* creates cumulative constraint and adds it to problem */
9871 	      SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9872 	            consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9873 	            SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
9874 	            SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
9875 	
9876 	      /* adjust the effective time horizon of the constraint */
9877 	      consdata->hmax = split;
9878 	
9879 	      assert(consdata->hmin < consdata->hmax);
9880 	
9881 	      /* for the statistic we count the number of time we decompose a cumulative constraint */
9882 	      SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ndecomps++ );
9883 	      (*naddconss)++;
9884 	   }
9885 	
9886 	   return SCIP_OKAY;
9887 	}
9888 	
9889 	
9890 	/** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9891 	 *
9892 	 *  (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9893 	 *      form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9894 	 *
9895 	 *  (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9896 	 *      before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9897 	 *      down-lock of the corresponding start time variable can be removed.
9898 	 *
9899 	 *  (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9900 	 *      locking the corresponding variable down, and the objective coefficient of the start time variable is not
9901 	 *      negative, than the job can be dual fixed to its earlier start time (est).
9902 	 *
9903 	 *  (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9904 	 *      corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9905 	 *      removing the values {est+1,...,hmin} form variable domain is dual feasible.
9906 	 *
9907 	 *  (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9908 	 *      (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9909 	 *      objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9910 	 *      form variable domain is dual feasible.
9911 	 *
9912 	 *  @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9913 	 *        the cumulative condition; The deletion has to be done later.
9914 	 */
9915 	static
9916 	SCIP_RETCODE presolveConsEst(
9917 	   SCIP*                 scip,               /**< SCIP data structure */
9918 	   int                   nvars,              /**< number of start time variables (activities) */
9919 	   SCIP_VAR**            vars,               /**< array of start time variables */
9920 	   int*                  durations,          /**< array of durations */
9921 	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
9922 	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
9923 	   SCIP_Bool*            downlocks,          /**< array to store if the variable has a down lock, or NULL */
9924 	   SCIP_Bool*            uplocks,            /**< array to store if the variable has an up lock, or NULL */
9925 	   SCIP_CONS*            cons,               /**< underlying constraint, or NULL */
9926 	   SCIP_Bool*            irrelevants,        /**< array mark those variables which are irrelevant for the cumulative condition */
9927 	   int*                  nfixedvars,         /**< pointer to store the number of fixed variables */
9928 	   int*                  nchgsides,          /**< pointer to store the number of changed sides */
9929 	   SCIP_Bool*            cutoff              /**< buffer to store whether a cutoff is detected */
9930 	   )
9931 	{
9932 	   SCIP_Real* downimpllbs;
9933 	   SCIP_Real* downimplubs;
9934 	   SCIP_Real* downproplbs;
9935 	   SCIP_Real* downpropubs;
9936 	   SCIP_Real* upimpllbs;
9937 	   SCIP_Real* upimplubs;
9938 	   SCIP_Real* upproplbs;
9939 	   SCIP_Real* uppropubs;
9940 	
9941 	   int firstminect;
9942 	   int secondminect;
9943 	   int v;
9944 	
9945 	   /* get temporary memory for storing probing results needed for step (4) and (5) */
9946 	   SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9947 	   SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9948 	   SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9949 	   SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9950 	   SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9951 	   SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9952 	   SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9953 	   SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9954 	
9955 	   assert(scip != NULL);
9956 	   assert(nvars > 1);
9957 	   assert(cons != NULL);
9958 	
9959 	   SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9960 	
9961 	   firstminect = INT_MAX;
9962 	   secondminect = INT_MAX;
9963 	
9964 	   /* compute the two smallest earlier completion times; which are needed for step (5) */
9965 	   for( v = 0; v < nvars; ++v )
9966 	   {
9967 	      int ect;
9968 	
9969 	      ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9970 	
9971 	      if( ect < firstminect )
9972 	      {
9973 	         secondminect = firstminect;
9974 	         firstminect = ect;
9975 	      }
9976 	      else if( ect < secondminect )
9977 	         secondminect = ect;
9978 	   }
9979 	
9980 	   /* loop over all jobs and check if one of the 5 reductions can be applied */
9981 	   for( v = 0; v < nvars; ++v )
9982 	   {
9983 	      SCIP_VAR* var;
9984 	      int duration;
9985 	
9986 	      int alternativelb;
9987 	      int minect;
9988 	      int est;
9989 	      int ect;
9990 	      int lst;
9991 	      int lct;
9992 	
9993 	      var = vars[v];
9994 	      assert(var != NULL);
9995 	
9996 	      duration = durations[v];
9997 	      assert(duration > 0);
9998 	
9999 	      /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10000	       * time (lct)
10001	       */
10002	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10003	      ect = est + duration;
10004	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10005	      lct = lst + duration;
10006	
10007	      /* compute the earliest completion time of all remaining jobs */
10008	      if( ect == firstminect )
10009	         minect = secondminect;
10010	      else
10011	         minect = firstminect;
10012	
10013	      /* compute potential alternative lower bound (step (4) and (5)) */
10014	      alternativelb = MAX(hmin+1, minect);
10015	      alternativelb = MIN(alternativelb, hmax);
10016	
10017	      if( lct <= hmin )
10018	      {
10019	         /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
10020	          * cumulative condition
10021	          */
10022	         SCIPdebugMsg(scip, "  variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10023	            SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10024	
10025	         /* mark variable to be irrelevant */
10026	         irrelevants[v] = TRUE;
10027	
10028	         /* for the statistic we count the number of jobs which are irrelevant */
10029	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10030	      }
10031	      else if( lst <= hmin && SCIPconsIsChecked(cons) )
10032	      {
10033	         /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
10034	          * so the down lock can be omitted
10035	          */
10036	
10037	         assert(downlocks != NULL);
10038	         assert(uplocks != NULL);
10039	
10040	         if( !uplocks[v] )
10041	         {
10042	            /* the variables has no up lock and we can also remove the down lock;
10043	             * => lst <= hmin and ect >= hmax
10044	             * => remove job and reduce capacity by the demand of that job
10045	             *
10046	             * We mark the job to be deletable. The removement together with the capacity reducion is done later
10047	             */
10048	
10049	            SCIPdebugMsg(scip, "  variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10050	               SCIPvarGetName(var), ect - duration, lst, duration);
10051	
10052	            /* mark variable to be irrelevant */
10053	            irrelevants[v] = TRUE;
10054	
10055	            /* for the statistic we count the number of jobs which always run during the effective horizon */
10056	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nalwaysruns++ );
10057	         }
10058	
10059	         if( downlocks[v] )
10060	         {
10061	            SCIPdebugMsg(scip, "  remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10062	               SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10063	
10064	            SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10065	            downlocks[v] = FALSE;
10066	            (*nchgsides)++;
10067	
10068	            /* for the statistic we count the number of removed locks */
10069	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nremovedlocks++ );
10070	         }
10071	      }
10072	      else if( ect <= hmin )
10073	      {
10074	         /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10075	          * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10076	          * removed form the cumulative condition after it was fixed to its earliest start time
10077	          */
10078	
10079	         /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10080	          * bound;
10081	          */
10082	         if( downlocks != NULL && SCIPconsIsChecked(cons) )
10083	         {
10084	            /* fix integer start time variable if possible to it lower bound */
10085	            SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10086	         }
10087	
10088	         if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10089	         {
10090	            SCIPdebugMsg(scip, "  variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10091	               SCIPvarGetName(var), ect - duration, lst, duration);
10092	
10093	            /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10094	            assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10095	
10096	            /* mark variable to be irrelevant */
10097	            irrelevants[v] = TRUE;
10098	
10099	            /* for the statistic we count the number of jobs which are dual fixed */
10100	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ndualfixs++ );
10101	         }
10102	      }
10103	      else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10104	      {
10105	         assert(downlocks != NULL);
10106	
10107	         /* check step (4) and (5) */
10108	
10109	         /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10110	          * is in favor of rounding the variable down
10111	          */
10112	         if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10113	         {
10114	            SCIP_Bool roundable;
10115	
10116	            SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10117	
10118	            if( roundable )
10119	            {
10120	               if( alternativelb > lst )
10121	               {
10122	                  SCIP_Bool infeasible;
10123	                  SCIP_Bool fixed;
10124	
10125	                  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10126	                  assert(!infeasible);
10127	                  assert(fixed);
10128	
10129	                  (*nfixedvars)++;
10130	
10131	                  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10132	                   * constraints
10133	                   */
10134	                  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ndualbranchs++ );
10135	               }
10136	               else
10137	               {
10138	                  SCIP_Bool success;
10139	
10140	                  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10141	                   * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10142	                   * infeasible we can apply the dual reduction; otherwise we do nothing
10143	                   */
10144	                  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10145	                        downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10146	                        nfixedvars, &success, cutoff) );
10147	
10148	                  if( success )
10149	                  {
10150	                     SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ndualbranchs++ );
10151	                  }
10152	               }
10153	            }
10154	         }
10155	      }
10156	
10157	      SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10158	         SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10159	   }
10160	
10161	   /* free temporary memory */
10162	   SCIPfreeBufferArray(scip, &uppropubs);
10163	   SCIPfreeBufferArray(scip, &upproplbs);
10164	   SCIPfreeBufferArray(scip, &upimplubs);
10165	   SCIPfreeBufferArray(scip, &upimpllbs);
10166	   SCIPfreeBufferArray(scip, &downpropubs);
10167	   SCIPfreeBufferArray(scip, &downproplbs);
10168	   SCIPfreeBufferArray(scip, &downimplubs);
10169	   SCIPfreeBufferArray(scip, &downimpllbs);
10170	
10171	   return SCIP_OKAY;
10172	}
10173	
10174	/** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10175	 *
10176	 *  (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10177	 *      form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10178	 *
10179	 *  (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10180	 *      before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10181	 *      up-lock of the corresponding start time variable can be removed.
10182	 *
10183	 *  (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10184	 *      locking the corresponding variable up, and the objective coefficient of the start time variable is not
10185	 *      positive, than the job can be dual fixed to its latest start time (lst).
10186	 *
10187	 *  (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10188	 *      corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10189	 *      removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10190	 *      of the corresponding job).
10191	
10192	 *  (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10193	 *      (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10194	 *      objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10195	 *      ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10196	 *
10197	 *  @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10198	 *        the cumulative condition; The deletion has to be done later.
10199	 */
10200	static
10201	SCIP_RETCODE presolveConsLct(
10202	   SCIP*                 scip,               /**< SCIP data structure */
10203	   int                   nvars,              /**< number of start time variables (activities) */
10204	   SCIP_VAR**            vars,               /**< array of start time variables */
10205	   int*                  durations,          /**< array of durations */
10206	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
10207	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
10208	   SCIP_Bool*            downlocks,          /**< array to store if the variable has a down lock, or NULL */
10209	   SCIP_Bool*            uplocks,            /**< array to store if the variable has an up lock, or NULL */
10210	   SCIP_CONS*            cons,               /**< underlying constraint, or NULL */
10211	   SCIP_Bool*            irrelevants,        /**< array mark those variables which are irrelevant for the cumulative condition */
10212	   int*                  nfixedvars,         /**< pointer to counter which is increased by the number of deduced variable fixations */
10213	   int*                  nchgsides,          /**< pointer to store the number of changed sides */
10214	   SCIP_Bool*            cutoff              /**< buffer to store whether a cutoff is detected */
10215	   )
10216	{
10217	   SCIP_Real* downimpllbs;
10218	   SCIP_Real* downimplubs;
10219	   SCIP_Real* downproplbs;
10220	   SCIP_Real* downpropubs;
10221	   SCIP_Real* upimpllbs;
10222	   SCIP_Real* upimplubs;
10223	   SCIP_Real* upproplbs;
10224	   SCIP_Real* uppropubs;
10225	
10226	   int firstmaxlst;
10227	   int secondmaxlst;
10228	   int v;
10229	
10230	   /* get temporary memory for storing probing results needed for step (4) and (5) */
10231	   SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10232	   SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10233	   SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10234	   SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10235	   SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10236	   SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10237	   SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10238	   SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10239	
10240	   assert(scip != NULL);
10241	   assert(nvars > 1);
10242	   assert(cons != NULL);
10243	
10244	   SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10245	
10246	   firstmaxlst = INT_MIN;
10247	   secondmaxlst = INT_MIN;
10248	
10249	   /* compute the two largest latest start times; which are needed for step (5) */
10250	   for( v = 0; v < nvars; ++v )
10251	   {
10252	      int lst;
10253	
10254	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10255	
10256	      if( lst > firstmaxlst )
10257	      {
10258	         secondmaxlst = firstmaxlst;
10259	         firstmaxlst = lst;
10260	      }
10261	      else if( lst > secondmaxlst )
10262	         secondmaxlst = lst;
10263	   }
10264	
10265	   /* loop over all jobs and check if one of the 5 reductions can be applied */
10266	   for( v = 0; v < nvars; ++v )
10267	   {
10268	      SCIP_VAR* var;
10269	      int duration;
10270	
10271	      int alternativeub;
10272	      int maxlst;
10273	      int est;
10274	      int ect;
10275	      int lst;
10276	
10277	      var = vars[v];
10278	      assert(var != NULL);
10279	
10280	      duration = durations[v];
10281	      assert(duration > 0);
10282	
10283	      /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10284	       * time (lct)
10285	       */
10286	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10287	      ect = est + duration;
10288	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10289	
10290	      /* compute the latest start time of all remaining jobs */
10291	      if( lst == firstmaxlst )
10292	         maxlst = secondmaxlst;
10293	      else
10294	         maxlst = firstmaxlst;
10295	
10296	      /* compute potential alternative upper bound (step (4) and (5)) */
10297	      alternativeub = MIN(hmax - 1, maxlst)  - duration;
10298	      alternativeub = MAX(alternativeub, hmin);
10299	
10300	      if( est >= hmax )
10301	      {
10302	         /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10303	          * cumulative condition
10304	          */
10305	         SCIPdebugMsg(scip, "  variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10306	            SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10307	
10308	         /* mark variable to be irrelevant */
10309	         irrelevants[v] = TRUE;
10310	
10311	         /* for the statistic we count the number of jobs which are irrelevant */
10312	         SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10313	      }
10314	      else if( ect >= hmax && SCIPconsIsChecked(cons) )
10315	      {
10316	         assert(downlocks != NULL);
10317	         assert(uplocks != NULL);
10318	
10319	         /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10320	          * so the up lock can be omitted
10321	          */
10322	
10323	         if( !downlocks[v] )
10324	         {
10325	            /* the variables has no down lock and we can also remove the up lock;
10326	             * => lst <= hmin and ect >= hmax
10327	             * => remove job and reduce capacity by the demand of that job
10328	             */
10329	            SCIPdebugMsg(scip, "  variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10330	               SCIPvarGetName(var), est, lst, duration);
10331	
10332	            /* mark variable to be irrelevant */
10333	            irrelevants[v] = TRUE;
10334	
10335	            /* for the statistic we count the number of jobs which always run during the effective horizon */
10336	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nalwaysruns++ );
10337	         }
10338	
10339	         if( uplocks[v] )
10340	         {
10341	            SCIPdebugMsg(scip, "  remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10342	               SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10343	
10344	            SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10345	            uplocks[v] = FALSE;
10346	            (*nchgsides)++;
10347	
10348	            /* for the statistic we count the number of removed locks */
10349	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nremovedlocks++ );
10350	         }
10351	      }
10352	      else if( lst >= hmax )
10353	      {
10354	         /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10355	          * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10356	          * removed form the cumulative condition after it was fixed to its latest start time
10357	          */
10358	
10359	         /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10360	          * bound
10361	          */
10362	         if( uplocks != NULL && SCIPconsIsChecked(cons) )
10363	         {
10364	            /* fix integer start time variable if possible to its upper bound */
10365	            SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10366	         }
10367	
10368	         if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10369	         {
10370	            SCIPdebugMsg(scip, "  variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10371	               SCIPvarGetName(var), est, lst, duration);
10372	
10373	            /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10374	            assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10375	
10376	            /* mark variable to be irrelevant */
10377	            irrelevants[v] = TRUE;
10378	
10379	            /* for the statistic we count the number of jobs which are dual fixed */
10380	            SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ndualfixs++ );
10381	         }
10382	      }
10383	      else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10384	      {
10385	         assert(uplocks != NULL);
10386	
10387	         /* check step (4) and (5) */
10388	
10389	         /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10390	          * is in favor of rounding the variable down
10391	          */
10392	         if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10393	         {
10394	            SCIP_Bool roundable;
10395	
10396	            SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10397	
10398	            if( roundable )
10399	            {
10400	               if( alternativeub < est )
10401	               {
10402	                  SCIP_Bool infeasible;
10403	                  SCIP_Bool fixed;
10404	
10405	                  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10406	                  assert(!infeasible);
10407	                  assert(fixed);
10408	
10409	                  (*nfixedvars)++;
10410	
10411	                  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10412	                   * constraints
10413	                   */
10414	                  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ndualbranchs++ );
10415	               }
10416	               else
10417	               {
10418	                  SCIP_Bool success;
10419	
10420	                  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10421	                   * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10422	                   * in infeasible we can apply the dual reduction; otherwise we do nothing
10423	                   */
10424	                  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10425	                        downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10426	                        nfixedvars, &success, cutoff) );
10427	
10428	                  if( success )
10429	                  {
10430	                     SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ndualbranchs++ );
10431	                  }
10432	               }
10433	            }
10434	         }
10435	      }
10436	   }
10437	
10438	   /* free temporary memory */
10439	   SCIPfreeBufferArray(scip, &uppropubs);
10440	   SCIPfreeBufferArray(scip, &upproplbs);
10441	   SCIPfreeBufferArray(scip, &upimplubs);
10442	   SCIPfreeBufferArray(scip, &upimpllbs);
10443	   SCIPfreeBufferArray(scip, &downpropubs);
10444	   SCIPfreeBufferArray(scip, &downproplbs);
10445	   SCIPfreeBufferArray(scip, &downimplubs);
10446	   SCIPfreeBufferArray(scip, &downimpllbs);
10447	
10448	   return SCIP_OKAY;
10449	}
10450	
10451	/** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10452	static
10453	SCIP_RETCODE presolveConsEffectiveHorizon(
10454	   SCIP*                 scip,               /**< SCIP data structure */
10455	   SCIP_CONS*            cons,               /**< cumulative constraint */
10456	   int*                  nfixedvars,         /**< pointer to store the number of fixed variables */
10457	   int*                  nchgcoefs,          /**< pointer to store the number of changed coefficients */
10458	   int*                  nchgsides,          /**< pointer to store the number of changed sides */
10459	   SCIP_Bool*            cutoff              /**< pointer to store if a cutoff was detected */
10460	   )
10461	{
10462	   SCIP_CONSDATA* consdata;
10463	   SCIP_Bool* irrelevants;
10464	   int nvars;
10465	   int v;
10466	
10467	   assert(scip != NULL);
10468	   assert(cons != NULL);
10469	   assert(!(*cutoff));
10470	
10471	   consdata = SCIPconsGetData(cons);
10472	   assert(consdata != NULL);
10473	
10474	   nvars = consdata->nvars;
10475	
10476	   if( nvars <= 1 )
10477	      return SCIP_OKAY;
10478	
10479	   SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10480	   BMSclearMemoryArray(irrelevants, nvars);
10481	
10482	   /* presolve constraint form the earlier start time point of view */
10483	   SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10484	         consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10485	         irrelevants, nfixedvars, nchgsides, cutoff) );
10486	
10487	   /* presolve constraint form the latest completion time point of view */
10488	   SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10489	         consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10490	         irrelevants, nfixedvars, nchgsides, cutoff) );
10491	
10492	   /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10493	    * order to ensure a correct behaviour
10494	    */
10495	   for( v = nvars-1; v >= 0; --v )
10496	   {
10497	      if( irrelevants[v] )
10498	      {
10499	         SCIP_VAR* var;
10500	         int ect;
10501	         int lst;
10502	
10503	         var = consdata->vars[v];
10504	         assert(var != NULL);
10505	
10506	         ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10507	         lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10508	
10509	         /* check if the jobs runs completely during the effective horizon */
10510	         if( lst <= consdata->hmin && ect >= consdata->hmax )
10511	         {
10512	            if( consdata->capacity < consdata->demands[v] )
10513	            {
10514	               *cutoff = TRUE;
10515	               break;
10516	            }
10517	
10518	            consdata->capacity -= consdata->demands[v];
10519	            consdata->varbounds = FALSE;
10520	         }
10521	
10522	         SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10523	         (*nchgcoefs)++;
10524	      }
10525	   }
10526	
10527	   SCIPfreeBufferArray(scip, &irrelevants);
10528	
10529	   return SCIP_OKAY;
10530	}
10531	
10532	/** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10533	static
10534	void collectDemands(
10535	   SCIP*                 scip,               /**< SCIP data structure */
10536	   SCIP_CONSDATA*        consdata,           /**< constraint data */
10537	   int*                  startindices,       /**< permutation with rspect to the start times */
10538	   int                   curtime,            /**< current point in time */
10539	   int                   nstarted,           /**< number of jobs that start before the curtime or at curtime */
10540	   int                   nfinished,          /**< number of jobs that finished before curtime or at curtime */
10541	   SCIP_Longint**        demands,            /**< pointer to array storing the demands */
10542	   int*                  ndemands            /**< pointer to store the number of different demands */
10543	   )
10544	{
10545	   int startindex;
10546	   int ncountedvars;
10547	
10548	   assert(demands != NULL);
10549	   assert(ndemands != NULL);
10550	
10551	   ncountedvars = 0;
10552	   startindex = nstarted - 1;
10553	
10554	   *ndemands = 0;
10555	
10556	   /* search for the (nstarted - nfinished) jobs which are active at curtime */
10557	   while( nstarted - nfinished > ncountedvars )
10558	   {
10559	      SCIP_VAR* var;
10560	      int endtime;
10561	      int varidx;
10562	
10563	      /* collect job information */
10564	      varidx = startindices[startindex];
10565	      assert(varidx >= 0 && varidx < consdata->nvars);
10566	
10567	      var = consdata->vars[varidx];
10568	      assert(var != NULL);
10569	
10570	      endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10571	
10572	      /* check the end time of this job is larger than the curtime; in this case the job is still running */
10573	      if( endtime > curtime )
10574	      {
10575	         if( consdata->demands[varidx] < consdata->capacity )
10576	         {
10577	            (*demands)[*ndemands] = consdata->demands[varidx];
10578	            (*ndemands)++;
10579	         }
10580	         ncountedvars++;
10581	      }
10582	
10583	      startindex--;
10584	   }
10585	}
10586	
10587	/** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10588	 *  constraint
10589	 */
10590	static
10591	SCIP_RETCODE getHighestCapacityUsage(
10592	   SCIP*                 scip,               /**< SCIP data structure */
10593	   SCIP_CONS*            cons,               /**< constraint to be checked */
10594	   int*                  startindices,       /**< permutation with rspect to the start times */
10595	   int                   curtime,            /**< current point in time */
10596	   int                   nstarted,           /**< number of jobs that start before the curtime or at curtime */
10597	   int                   nfinished,          /**< number of jobs that finished before curtime or at curtime */
10598	   int*                  bestcapacity        /**< pointer to store the maximum possible capacity usage */
10599	   )
10600	{
10601	   SCIP_CONSDATA* consdata;
10602	   SCIP_Longint* demands;
10603	   SCIP_Real* profits;
10604	   int* items;
10605	   int ndemands;
10606	   SCIP_Bool success;
10607	   SCIP_Real solval;
10608	   int j;
10609	   assert(nstarted > nfinished);
10610	
10611	   consdata = SCIPconsGetData(cons);
10612	   assert(consdata != NULL);
10613	   assert(consdata->nvars > 0);
10614	   assert(consdata->capacity > 0);
10615	
10616	   SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10617	   ndemands = 0;
10618	
10619	   /* get demand array to initialize knapsack problem */
10620	   collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10621	
10622	   /* create array for profits */
10623	   SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10624	   SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10625	   for( j = 0; j < ndemands; ++j )
10626	   {
10627	      profits[j] = (SCIP_Real) demands[j];
10628	      items[j] = j;/* this is only a dummy value*/
10629	   }
10630	
10631	   /* solve knapsack problem and get maximum capacity usage <= capacity */
10632	   SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10633	         items, NULL, NULL, NULL, NULL, &solval, &success) );
10634	
10635	   assert(SCIPisFeasIntegral(scip, solval));
10636	
10637	   /* store result */
10638	   *bestcapacity = SCIPconvertRealToInt(scip, solval);
10639	
10640	   SCIPfreeBufferArray(scip, &items);
10641	   SCIPfreeBufferArray(scip, &profits);
10642	   SCIPfreeBufferArray(scip, &demands);
10643	
10644	   return SCIP_OKAY;
10645	}
10646	
10647	/** try to tighten the capacity
10648	 *  -- using DP for knapsack, we find the maximum possible capacity usage
10649	 *  -- neglects hmin and hmax, such that it is also able to check solutions globally
10650	 */
10651	static
10652	SCIP_RETCODE tightenCapacity(
10653	   SCIP*                 scip,               /**< SCIP data structure */
10654	   SCIP_CONS*            cons,               /**< cumulative constraint */
10655	   int*                  nchgcoefs,          /**< pointer to count total number of changed coefficients */
10656	   int*                  nchgsides           /**< pointer to store the number of changed sides */
10657	   )
10658	{
10659	   SCIP_CONSDATA* consdata;
10660	   int* starttimes;         /* stores when each job is starting */
10661	   int* endtimes;           /* stores when each job ends */
10662	   int* startindices;       /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10663	   int* endindices;         /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10664	
10665	   int nvars;               /* number of activities for this constraint */
10666	   int freecapacity;        /* remaining capacity */
10667	   int curtime;             /* point in time which we are just checking */
10668	   int endindex;            /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10669	
10670	   int bestcapacity;
10671	
10672	   int j;
10673	
10674	   assert(scip != NULL);
10675	   assert(cons != NULL);
10676	   assert(nchgsides != NULL);
10677	
10678	   consdata = SCIPconsGetData(cons);
10679	   assert(consdata != NULL);
10680	
10681	   nvars = consdata->nvars;
10682	
10683	   /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10684	   if( nvars <= 1 || consdata->capacity <= 1 )
10685	      return SCIP_OKAY;
10686	
10687	   assert(consdata->vars != NULL);
10688	
10689	   SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10690	      SCIPconsGetName(cons), consdata->capacity);
10691	
10692	   SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10693	   SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10694	   SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10695	   SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10696	
10697	   /* create event point arrays */
10698	   createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10699	      starttimes, endtimes, startindices, endindices, FALSE);
10700	
10701	   bestcapacity = 1;
10702	   endindex = 0;
10703	   freecapacity = consdata->capacity;
10704	
10705	   /* check each startpoint of a job whether the capacity is kept or not */
10706	   for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10707	   {
10708	      curtime = starttimes[j];
10709	      SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10710	
10711	      /* remove the capacity requirments for all job which start at the curtime */
10712	      subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10713	
10714	      /* add the capacity requirments for all job which end at the curtime */
10715	      addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10716	
10717	      assert(freecapacity <= consdata->capacity);
10718	      assert(endindex <= nvars);
10719	
10720	      /* endindex - points to the next job which will finish */
10721	      /* j - points to the last job that has been released */
10722	
10723	      /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10724	      if( freecapacity < 0 )
10725	      {
10726	         int newcapacity;
10727	
10728	         newcapacity = 1;
10729	
10730	         /* get best possible upper bound on capacity usage */
10731	         SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10732	
10733	         /* update bestcapacity */
10734	         bestcapacity = MAX(bestcapacity, newcapacity);
10735	         SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10736	      }
10737	
10738	      /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10739	      if( freecapacity > 0 && freecapacity != consdata->capacity )
10740	      {
10741	         bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10742	         SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10743	      }
10744	
10745	      /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10746	      if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10747	      {
10748	         /* if demands[startindices[j]] == cap then exactly that job is running */
10749	         SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10750	         bestcapacity = consdata->capacity;
10751	         break;
10752	      }
10753	   }  /*lint --e{850}*/
10754	
10755	   /* free all buffer arrays */
10756	   SCIPfreeBufferArray(scip, &endindices);
10757	   SCIPfreeBufferArray(scip, &startindices);
10758	   SCIPfreeBufferArray(scip, &endtimes);
10759	   SCIPfreeBufferArray(scip, &starttimes);
10760	
10761	   /* check whether capacity can be tightened and whether demands need to be adjusted */
10762	   if( bestcapacity < consdata->capacity )
10763	   {
10764	      SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10765	
10766	      SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10767	         SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10768	
10769	      for( j = 0; j < nvars; ++j )
10770	      {
10771	         if( consdata->demands[j] == consdata->capacity )
10772	         {
10773	            consdata->demands[j] = bestcapacity;
10774	            (*nchgcoefs)++;
10775	         }
10776	      }
10777	
10778	      consdata->capacity = bestcapacity;
10779	      (*nchgsides)++;
10780	
10781	      SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10782	
10783	      consdata->varbounds = FALSE;
10784	   }
10785	
10786	   return SCIP_OKAY;
10787	}
10788	
10789	/** tries to change coefficients:
10790	 *        demand_j < cap && all other parallel jobs in conflict
10791	 *         ==> set demand_j := cap
10792	 */
10793	static
10794	SCIP_RETCODE tightenCoefs(
10795	   SCIP*                 scip,               /**< SCIP data structure */
10796	   SCIP_CONS*            cons,               /**< cumulative constraint */
10797	   int*                  nchgcoefs           /**< pointer to count total number of changed coefficients */
10798	   )
10799	{
10800	   SCIP_CONSDATA* consdata;
10801	   int nvars;
10802	   int j;
10803	   int oldnchgcoefs;
10804	   int mindemand;
10805	
10806	   assert(scip != NULL);
10807	   assert(cons != NULL);
10808	   assert(nchgcoefs != NULL);
10809	
10810	   /* get constraint data for some parameter testings only! */
10811	   consdata = SCIPconsGetData(cons);
10812	   assert(consdata != NULL);
10813	
10814	   nvars = consdata->nvars;
10815	   oldnchgcoefs = *nchgcoefs;
10816	
10817	   if( nvars <= 0 )
10818	      return SCIP_OKAY;
10819	
10820	   /* PRE1:
10821	    * check all jobs j whether: r_j + r_min > capacity holds
10822	    * if so: adjust r_j to capacity
10823	    */
10824	   mindemand = consdata->demands[0];
10825	   for( j = 0; j < nvars; ++j )
10826	   {
10827	      mindemand = MIN(mindemand, consdata->demands[j]);
10828	   }
10829	
10830	   /*check each job */
10831	   for( j = 0; j < nvars; ++j )
10832	   {
10833	      if( mindemand + consdata->demands[j] > consdata->capacity  && consdata->demands[j] < consdata->capacity )
10834	      {
10835	         SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10836	            consdata->demands[j], consdata->capacity);
10837	         consdata->demands[j] = consdata->capacity;
10838	         (*nchgcoefs)++;
10839	      }
10840	   }
10841	
10842	   /* PRE2:
10843	    * check for each job (with d_j < cap)
10844	    * whether it is disjunctive to all others over the time horizon
10845	    */
10846	   for( j = 0; j < nvars; ++j )
10847	   {
10848	      SCIP_Bool chgcoef;
10849	      int est_j;
10850	      int lct_j;
10851	      int i;
10852	
10853	      assert(consdata->demands[j] <= consdata->capacity);
10854	
10855	      if( consdata->demands[j] == consdata->capacity )
10856	         continue;
10857	
10858	      chgcoef = TRUE;
10859	
10860	      est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10861	      lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10862	
10863	      for( i = 0; i < nvars; ++i )
10864	      {
10865	         int est_i;
10866	         int lct_i;
10867	
10868	         if( i == j )
10869	            continue;
10870	
10871	         est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10872	         lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10873	
10874	         if( est_i >= lct_j || est_j >= lct_i )
10875	            continue;
10876	
10877	         if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10878	         {
10879	            chgcoef = FALSE;
10880	            break;
10881	         }
10882	      }
10883	
10884	      if( chgcoef )
10885	      {
10886	         SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10887	            consdata->demands[j], consdata->capacity);
10888	         consdata->demands[j] = consdata->capacity;
10889	         (*nchgcoefs)++;
10890	      }
10891	   }
10892	
10893	   if( (*nchgcoefs) > oldnchgcoefs )
10894	   {
10895	      SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10896	         (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10897	   }
10898	
10899	   return SCIP_OKAY;
10900	}
10901	
10902	#if 0
10903	/** try to reformulate constraint by replacing certain jobs */
10904	static
10905	SCIP_RETCODE reformulateCons(
10906	   SCIP*                 scip,               /**< SCIP data structure */
10907	   SCIP_CONS*            cons,               /**< cumulative constraint */
10908	   int*                  naggrvars           /**< pointer to store the number of aggregated variables */
10909	   )
10910	{
10911	   SCIP_CONSDATA* consdata;
10912	   int hmin;
10913	   int hmax;
10914	   int nvars;
10915	   int v;
10916	
10917	   consdata = SCIPconsGetData(cons);
10918	   assert(cons != NULL);
10919	
10920	   nvars = consdata->nvars;
10921	   assert(nvars > 1);
10922	
10923	   hmin = consdata->hmin;
10924	   hmax = consdata->hmax;
10925	   assert(hmin < hmax);
10926	
10927	   for( v = 0; v < nvars; ++v )
10928	   {
10929	      SCIP_VAR* var;
10930	      int duration;
10931	      int est;
10932	      int ect;
10933	      int lst;
10934	      int lct;
10935	
10936	      var = consdata->vars[v];
10937	      assert(var != NULL);
10938	
10939	      duration = consdata->durations[v];
10940	
10941	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10942	      ect = est + duration;
10943	      lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10944	      lct = lst + duration;
10945	
10946	      /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10947	      assert(lst > hmin || ect < hmax);
10948	
10949	      if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10950	      {
10951	         SCIP_VAR* aggrvar;
10952	         char name[SCIP_MAXSTRLEN];
10953	         SCIP_Bool infeasible;
10954	         SCIP_Bool redundant;
10955	         SCIP_Bool aggregated;
10956	         int shift;
10957	
10958	         shift = est - (hmin - lct + MIN(hmin, ect));
10959	         assert(shift > 0);
10960	         lst = hmin;
10961	         duration = hmin - lct;
10962	
10963	         SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10964	            SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10965	
10966	         (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10967	         SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10968	               SCIPvarIsInitial(var), SCIPvarIsRemovable(var), NULL, NULL, NULL, NULL, NULL) );
10969	         SCIP_CALL( SCIPaddVar(scip, var) );
10970	         SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10971	
10972	         assert(!infeasible);
10973	         assert(!redundant);
10974	         assert(aggregated);
10975	
10976	         /* replace variable */
10977	         consdata->durations[v] = duration;
10978	         consdata->vars[v] = aggrvar;
10979	
10980	         /* remove and add locks */
10981	         SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10982	         SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10983	
10984	         SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10985	
10986	         (*naggrvars)++;
10987	      }
10988	   }
10989	
10990	   return SCIP_OKAY;
10991	}
10992	#endif
10993	
10994	/** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10995	static
10996	SCIP_RETCODE createDisjuctiveCons(
10997	   SCIP*                 scip,               /**< SCIP data structure */
10998	   SCIP_CONS*            cons,               /**< cumulative constraint */
10999	   int*                  naddconss           /**< pointer to store the number of added constraints */
11000	   )
11001	{
11002	   SCIP_CONSDATA* consdata;
11003	   SCIP_VAR** vars;
11004	   int* durations;
11005	   int* demands;
11006	   int capacity;
11007	   int halfcapacity;
11008	   int mindemand;
11009	   int nvars;
11010	   int v;
11011	
11012	   consdata = SCIPconsGetData(cons);
11013	   assert(consdata != NULL);
11014	
11015	   capacity = consdata->capacity;
11016	
11017	   if( capacity == 1 )
11018	      return SCIP_OKAY;
11019	
11020	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
11021	   SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
11022	   SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
11023	
11024	   halfcapacity = capacity / 2;
11025	   mindemand = consdata->capacity;
11026	   nvars = 0;
11027	
11028	   /* collect all jobs with demand larger than half of the capacity */
11029	   for( v = 0; v < consdata->nvars; ++v )
11030	   {
11031	      if( consdata->demands[v] > halfcapacity )
11032	      {
11033	         vars[nvars] = consdata->vars[v];
11034	         demands[nvars] = 1;
11035	         durations[nvars] = consdata->durations[v];
11036	         nvars++;
11037	
11038	         mindemand = MIN(mindemand, consdata->demands[v]);
11039	      }
11040	   }
11041	
11042	   if( nvars > 0 )
11043	   {
11044	      /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11045	       * job is still to large to be scheduled in parallel
11046	       */
11047	      for( v = 0; v < consdata->nvars; ++v )
11048	      {
11049	         if( consdata->demands[v] > halfcapacity )
11050	            continue;
11051	
11052	         if( mindemand + consdata->demands[v] > capacity )
11053	         {
11054	            demands[nvars] = 1;
11055	            durations[nvars] = consdata->durations[v];
11056	            vars[nvars] = consdata->vars[v];
11057	            nvars++;
11058	
11059	            /* @todo create one cumulative constraint and look for another small demand */
11060	            break;
11061	         }
11062	      }
11063	
11064	      /* creates cumulative constraint and adds it to problem */
11065	      SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11066	            FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
11067	      (*naddconss)++;
11068	   }
11069	
11070	   SCIPfreeBufferArray(scip, &demands);
11071	   SCIPfreeBufferArray(scip, &durations);
11072	   SCIPfreeBufferArray(scip, &vars);
11073	
11074	   return SCIP_OKAY;
11075	}
11076	
11077	/** presolve given constraint */
11078	static
11079	SCIP_RETCODE presolveCons(
11080	   SCIP*                 scip,               /**< SCIP data structure */
11081	   SCIP_CONS*            cons,               /**< cumulative constraint */
11082	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
11083	   SCIP_PRESOLTIMING     presoltiming,       /**< timing of presolving call */
11084	   int*                  nfixedvars,         /**< pointer to store the number of fixed variables */
11085	#if 0
11086	   int*                  naggrvars,          /**< pointer to counter which is increased by the number of deduced variable aggregations */
11087	#endif
11088	   int*                  nchgbds,            /**< pointer to store the number of changed bounds */
11089	   int*                  ndelconss,          /**< pointer to store the number of deleted constraints */
11090	   int*                  naddconss,          /**< pointer to store the number of added constraints */
11091	   int*                  nchgcoefs,          /**< pointer to store the number of changed coefficients */
11092	   int*                  nchgsides,          /**< pointer to store the number of changed sides */
11093	   SCIP_Bool*            cutoff,             /**< pointer to store if a cutoff was detected */
11094	   SCIP_Bool*            unbounded           /**< pointer to store if the problem is unbounded */
11095	   )
11096	{
11097	   assert(!SCIPconsIsDeleted(cons));
11098	
11099	   /* only perform dual reductions on model constraints */
11100	   if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11101	   {
11102	      /* computes the effective horizon and checks if the constraint can be decomposed */
11103	      SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11104	
11105	      if( SCIPconsIsDeleted(cons) )
11106	         return SCIP_OKAY;
11107	
11108	      /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11109	       * fixings (dual reductions)
11110	       */
11111	      if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11112	      {
11113	         SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11114	
11115	         if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11116	            return SCIP_OKAY;
11117	      }
11118	
11119	      SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11120	
11121	      if( *cutoff || SCIPconsIsDeleted(cons) )
11122	         return SCIP_OKAY;
11123	   }
11124	
11125	   /* remove jobs which have a demand larger than the capacity */
11126	   SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11127	   assert((*cutoff) || checkDemands(scip, cons));
11128	
11129	   if( *cutoff )
11130	      return SCIP_OKAY;
11131	
11132	   if( conshdlrdata->normalize )
11133	   {
11134	      /* divide demands by their greatest common divisor */
11135	      normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11136	   }
11137	
11138	   /* delete constraint with one job */
11139	   SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11140	
11141	   if( *cutoff || SCIPconsIsDeleted(cons) )
11142	      return SCIP_OKAY;
11143	
11144	   if( conshdlrdata->coeftightening )
11145	   {
11146	      /* try to tighten the capacity */
11147	      SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11148	
11149	      /* try to tighten the coefficients */
11150	      SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11151	   }
11152	
11153	   assert(checkDemands(scip, cons) || *cutoff);
11154	
11155	#if 0
11156	   SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11157	#endif
11158	
11159	   return SCIP_OKAY;
11160	}
11161	
11162	/**@name TClique Graph callbacks
11163	 *
11164	 * @{
11165	 */
11166	
11167	/** tclique graph data */
11168	struct TCLIQUE_Graph
11169	{
11170	   SCIP_VAR**            vars;               /**< start time variables each of them is a node */
11171	   SCIP_HASHMAP*         varmap;             /**< variable map, mapping variable to indux in vars array */
11172	   SCIP_Bool**           precedencematrix;   /**< precedence adjacent matrix */
11173	   SCIP_Bool**           demandmatrix;       /**< demand adjacent matrix */
11174	   TCLIQUE_WEIGHT*       weights;            /**< weight of nodes */
11175	   int*                  ninarcs;            /**< number if in arcs for the precedence graph */
11176	   int*                  noutarcs;           /**< number if out arcs for the precedence graph */
11177	   int*                  durations;          /**< for each node the duration of the corresponding job */
11178	   int                   nnodes;             /**< number of nodes */
11179	   int                   size;               /**< size of the array */
11180	};
11181	
11182	/** gets number of nodes in the graph */
11183	static
11184	TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11185	{
11186	   assert(tcliquegraph != NULL);
11187	
11188	   return tcliquegraph->nnodes;
11189	}
11190	
11191	/** gets weight of nodes in the graph */
11192	static
11193	TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11194	{
11195	   assert(tcliquegraph != NULL);
11196	
11197	   return tcliquegraph->weights;
11198	}
11199	
11200	/** returns, whether the edge (node1, node2) is in the graph */
11201	static
11202	TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11203	{
11204	   assert(tcliquegraph != NULL);
11205	   assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11206	   assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11207	
11208	   /* check if an arc exits in the precedence graph */
11209	   if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11210	      return TRUE;
11211	
11212	   /* check if an edge exits in the non-overlapping graph */
11213	   if( tcliquegraph->demandmatrix[node1][node2] )
11214	      return TRUE;
11215	
11216	   return FALSE;
11217	}
11218	
11219	/** selects all nodes from a given set of nodes which are adjacent to a given node
11220	 *  and returns the number of selected nodes
11221	 */
11222	static
11223	TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11224	{
11225	   int nadjnodes;
11226	   int i;
11227	
11228	   assert(tcliquegraph != NULL);
11229	   assert(0 <= node && node < tcliquegraph->nnodes);
11230	   assert(nnodes == 0 || nodes != NULL);
11231	   assert(adjnodes != NULL);
11232	
11233	   nadjnodes = 0;
11234	
11235	   for( i = 0; i < nnodes; i++ )
11236	   {
11237	      /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11238	      assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11239	      assert(i == 0 || nodes[i-1] < nodes[i]);
11240	
11241	      /* check if an edge exists */
11242	      if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11243	      {
11244	         /* current node is adjacent to given node */
11245	         adjnodes[nadjnodes] = nodes[i];
11246	         nadjnodes++;
11247	      }
11248	   }
11249	
11250	   return nadjnodes;
11251	}
11252	
11253	/** generates cuts using a clique found by algorithm for maximum weight clique
11254	 *  and decides whether to stop generating cliques with the algorithm for maximum weight clique
11255	 */
11256	static
11257	TCLIQUE_NEWSOL(tcliqueNewsolClique)
11258	{  /*lint --e{715}*/
11259	   SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11260	}
11261	
11262	/** print the tclique graph */
11263	#if 0
11264	static
11265	void tcliquePrint(
11266	   SCIP*                 scip,               /**< SCIP data structure */
11267	   TCLIQUE_GRAPH*        tcliquegraph        /**< tclique graph */
11268	   )
11269	{
11270	   int nnodes;
11271	   int i;
11272	   int j;
11273	
11274	   nnodes = tcliquegraph->nnodes;
11275	
11276	   for( i = 0; i < nnodes; ++i )
11277	   {
11278	      for( j = 0; j < nnodes; ++j )
11279	      {
11280	         SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11281	      }
11282	      SCIPinfoMessage(scip, NULL, "\n");
11283	   }
11284	}
11285	#endif
11286	
11287	/** @} */
11288	
11289	/** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11290	 *  job corresponding to variable bound variable (vlbvar)
11291	 *
11292	 *  variable lower bound is given as:  var >= vlbcoef * vlbvar + vlbconst
11293	 */
11294	static
11295	SCIP_Bool impliesVlbPrecedenceCondition(
11296	   SCIP*                 scip,               /**< SCIP data structure */
11297	   SCIP_VAR*             vlbvar,             /**< variable which bounds the variable from below */
11298	   SCIP_Real             vlbcoef,            /**< variable bound coefficient */
11299	   SCIP_Real             vlbconst,           /**< variable bound constant */
11300	   int                   duration            /**< duration of the variable bound variable */
11301	   )
11302	{
11303	   if( SCIPisEQ(scip, vlbcoef, 1.0) )
11304	   {
11305	      if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11306	      {
11307	         /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11308	         return TRUE;
11309	      }
11310	   }
11311	   else
11312	   {
11313	      SCIP_Real bound;
11314	
11315	      bound = (duration -  vlbcoef) / (vlbcoef - 1.0);
11316	
11317	      if( SCIPisLT(scip, vlbcoef, 1.0) )
11318	      {
11319	         SCIP_Real ub;
11320	
11321	         ub = SCIPvarGetUbLocal(vlbvar);
11322	
11323	         /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11324	         if( SCIPisLE(scip, ub, bound) )
11325	            return TRUE;
11326	      }
11327	      else
11328	      {
11329	         SCIP_Real lb;
11330	
11331	         assert(SCIPisGT(scip, vlbcoef, 1.0));
11332	
11333	         lb = SCIPvarGetLbLocal(vlbvar);
11334	
11335	         /* if  vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11336	         if( SCIPisGE(scip, lb, bound) )
11337	            return TRUE;
11338	      }
11339	   }
11340	
11341	   return FALSE;
11342	}
11343	
11344	/** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11345	 *  job corresponding to variable which is bounded (var)
11346	 *
11347	 *  variable upper bound is given as:  var <= vubcoef * vubvar + vubconst
11348	 */
11349	static
11350	SCIP_Bool impliesVubPrecedenceCondition(
11351	   SCIP*                 scip,               /**< SCIP data structure */
11352	   SCIP_VAR*             var,                /**< variable which is bound from above */
11353	   SCIP_Real             vubcoef,            /**< variable bound coefficient */
11354	   SCIP_Real             vubconst,           /**< variable bound constant */
11355	   int                   duration            /**< duration of the variable which is bounded from above */
11356	   )
11357	{
11358	   SCIP_Real vlbcoef;
11359	   SCIP_Real vlbconst;
11360	
11361	   /* convert the variable upper bound into an variable lower bound */
11362	   vlbcoef = 1.0 / vubcoef;
11363	   vlbconst = -vubconst / vubcoef;
11364	
11365	   return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11366	}
11367	
11368	/** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11369	 *  others an index larger than the number if active variables
11370	 */
11371	static
11372	SCIP_RETCODE getNodeIdx(
11373	   SCIP*                 scip,               /**< SCIP data structure */
11374	   TCLIQUE_GRAPH*        tcliquegraph,       /**< incompatibility graph */
11375	   SCIP_VAR*             var,                /**< variable for which we want the index */
11376	   int*                  idx                 /**< pointer to store the index */
11377	   )
11378	{
11379	   (*idx) = SCIPvarGetProbindex(var);
11380	
11381	   if( (*idx) == -1 )
11382	   {
11383	      if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11384	      {
11385	         (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11386	      }
11387	      else
11388	      {
11389	         int pos;
11390	         int v;
11391	
11392	         /**@todo we might want to add the aggregation path to graph */
11393	
11394	         /* check if we have to realloc memory */
11395	         if( tcliquegraph->size == tcliquegraph->nnodes )
11396	         {
11397	            int size;
11398	
11399	            size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11400	            tcliquegraph->size = size;
11401	
11402	            SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11403	            SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11404	            SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11405	            SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11406	            SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11407	
11408	            for( v = 0; v < tcliquegraph->nnodes; ++v )
11409	            {
11410	               SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11411	               SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11412	            }
11413	         }
11414	         assert(tcliquegraph->nnodes < tcliquegraph->size);
11415	
11416	         pos = tcliquegraph->nnodes;
11417	         assert(pos >= 0);
11418	
11419	         tcliquegraph->durations[pos] = 0;
11420	         tcliquegraph->weights[pos] = 0;
11421	         tcliquegraph->vars[pos] = var;
11422	
11423	         SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11424	         BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11425	
11426	         SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11427	         BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11428	
11429	         SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11430	
11431	         tcliquegraph->nnodes++;
11432	
11433	         for( v = 0; v < tcliquegraph->nnodes; ++v )
11434	         {
11435	            tcliquegraph->precedencematrix[v][pos] = 0;
11436	            tcliquegraph->demandmatrix[v][pos] = 0;
11437	         }
11438	
11439	         (*idx) = tcliquegraph->nnodes;
11440	      }
11441	   }
11442	   else
11443	   {
11444	      assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11445	   }
11446	
11447	   assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11448	
11449	   return SCIP_OKAY;
11450	}
11451	
11452	/** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11453	 *
11454	 *  Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11455	 *  variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11456	 *
11457	 *  (i)   b = 1 and c  >= d
11458	 *  (ii)  b > 1 and lb(x) >= (d - c)/(b - 1)
11459	 *  (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11460	 *
11461	 */
11462	static
11463	SCIP_RETCODE projectVbd(
11464	   SCIP*                 scip,               /**< SCIP data structure */
11465	   TCLIQUE_GRAPH*        tcliquegraph        /**< incompatibility graph */
11466	   )
11467	{
11468	   SCIP_VAR** vars;
11469	   int nvars;
11470	   int v;
11471	
11472	   vars = SCIPgetVars(scip);
11473	   nvars = SCIPgetNVars(scip);
11474	
11475	   /* try to project each arc of the variable bound graph to precedence condition */
11476	   for( v = 0; v < nvars; ++v )
11477	   {
11478	      SCIP_VAR** vbdvars;
11479	      SCIP_VAR* var;
11480	      SCIP_Real* vbdcoefs;
11481	      SCIP_Real* vbdconsts;
11482	      int nvbdvars;
11483	      int idx1;
11484	      int b;
11485	
11486	      var = vars[v];
11487	      assert(var != NULL);
11488	
11489	      SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11490	      assert(idx1 >= 0);
11491	
11492	      if( tcliquegraph->durations[idx1] == 0 )
11493	         continue;
11494	
11495	      vbdvars = SCIPvarGetVlbVars(var);
11496	      vbdcoefs = SCIPvarGetVlbCoefs(var);
11497	      vbdconsts = SCIPvarGetVlbConstants(var);
11498	      nvbdvars = SCIPvarGetNVlbs(var);
11499	
11500	      for( b = 0; b < nvbdvars; ++b )
11501	      {
11502	         int idx2;
11503	
11504	         SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11505	         assert(idx2 >= 0);
11506	
11507	         if( tcliquegraph->durations[idx2] == 0 )
11508	            continue;
11509	
11510	         if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11511	            tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11512	      }
11513	
11514	      vbdvars = SCIPvarGetVubVars(var);
11515	      vbdcoefs = SCIPvarGetVubCoefs(var);
11516	      vbdconsts = SCIPvarGetVubConstants(var);
11517	      nvbdvars = SCIPvarGetNVubs(var);
11518	
11519	      for( b = 0; b < nvbdvars; ++b )
11520	      {
11521	         int idx2;
11522	
11523	         SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11524	         assert(idx2 >= 0);
11525	
11526	         if( tcliquegraph->durations[idx2] == 0 )
11527	            continue;
11528	
11529	         if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11530	            tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11531	      }
11532	
11533	      for( b = v+1; b < nvars; ++b )
11534	      {
11535	         int idx2;
11536	
11537	         SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11538	         assert(idx2 >= 0);
11539	
11540	         if( tcliquegraph->durations[idx2] == 0 )
11541	            continue;
11542	
11543	         /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11544	         if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11545	            tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11546	
11547	         /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11548	         if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11549	            tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11550	      }
11551	   }
11552	
11553	   return SCIP_OKAY;
11554	}
11555	
11556	/** compute the transitive closer of the given graph and the number of in and out arcs */
11557	static
11558	void transitiveClosure(
11559	   SCIP_Bool**           adjmatrix,          /**< adjacent matrix */
11560	   int*                  ninarcs,            /**< array to store the number of in arcs */
11561	   int*                  noutarcs,           /**< array to store the number of out arcs */
11562	   int                   nnodes              /**< number if nodes */
11563	   )
11564	{
11565	   int i;
11566	   int j;
11567	   int k;
11568	
11569	   for( i = 0; i < nnodes; ++i )
11570	   {
11571	      for( j = 0; j < nnodes; ++j )
11572	      {
11573	         if( adjmatrix[i][j] )
11574	         {
11575	            ninarcs[j]++;
11576	            noutarcs[i]++;
11577	
11578	            for( k = 0; k < nnodes; ++k )
11579	            {
11580	               if( adjmatrix[j][k] )
11581	                  adjmatrix[i][k] = TRUE;
11582	            }
11583	         }
11584	      }
11585	   }
11586	}
11587	
11588	/** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11589	static
11590	SCIP_RETCODE constraintNonOverlappingGraph(
11591	   SCIP*                 scip,               /**< SCIP data structure */
11592	   TCLIQUE_GRAPH*        tcliquegraph,       /**< incompatibility graph */
11593	   SCIP_CONS**           conss,              /**< array of cumulative constraints */
11594	   int                   nconss              /**< number of cumulative constraints */
11595	   )
11596	{
11597	   int c;
11598	
11599	   /* use the cumulative constraints to initialize the none overlapping graph */
11600	   for( c = 0; c < nconss; ++c )
11601	   {
11602	      SCIP_CONSDATA* consdata;
11603	      SCIP_VAR** vars;
11604	      int* demands;
11605	      int capacity;
11606	      int nvars;
11607	      int i;
11608	
11609	      consdata = SCIPconsGetData(conss[c]);
11610	      assert(consdata != NULL);
11611	
11612	      vars = consdata->vars;
11613	      demands = consdata->demands;
11614	
11615	      nvars = consdata->nvars;
11616	      capacity = consdata->capacity;
11617	
11618	      SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11619	
11620	      /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11621	      for( i = 0; i < nvars; ++i )
11622	      {
11623	         int idx1;
11624	         int j;
11625	
11626	         SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11627	         assert(idx1 >= 0);
11628	
11629	         if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11630	            continue;
11631	
11632	         for( j = i+1; j < nvars; ++j )
11633	         {
11634	            assert(consdata->durations[j] > 0);
11635	
11636	            if( demands[i] + demands[j] > capacity )
11637	            {
11638	               int idx2;
11639	               int est1;
11640	               int est2;
11641	               int lct1;
11642	               int lct2;
11643	
11644	               /* check if the effective horizon is large enough */
11645	               est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11646	               est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11647	
11648	               /* at least one of the jobs needs to start at hmin or later */
11649	               if( est1 < consdata->hmin && est2 < consdata->hmin )
11650	                  continue;
11651	
11652	               lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11653	               lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11654	
11655	               /* at least one of the jobs needs to finish not later then hmin */
11656	               if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11657	                  continue;
11658	
11659	               SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11660	               assert(idx2 >= 0);
11661	               assert(idx1 != idx2);
11662	
11663	               if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11664	                  continue;
11665	
11666	               SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11667	
11668	               assert(tcliquegraph->durations[idx1] > 0);
11669	               assert(tcliquegraph->durations[idx2] > 0);
11670	
11671	               tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11672	               tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11673	            }
11674	         }
11675	      }
11676	   }
11677	
11678	   return SCIP_OKAY;
11679	}
11680	
11681	/** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11682	 *  of jobs cannot run in parallel
11683	 */
11684	static
11685	SCIP_RETCODE constructIncompatibilityGraph(
11686	   SCIP*                 scip,               /**< SCIP data structure */
11687	   TCLIQUE_GRAPH*        tcliquegraph,       /**< incompatibility graph */
11688	   SCIP_CONS**           conss,              /**< array of cumulative constraints */
11689	   int                   nconss              /**< number of cumulative constraints */
11690	   )
11691	{
11692	   assert(scip != NULL);
11693	   assert(tcliquegraph != NULL);
11694	
11695	   /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11696	   SCIP_CALL( projectVbd(scip, tcliquegraph) );
11697	
11698	   /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11699	   transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11700	
11701	   /* constraints non-overlapping graph */
11702	   SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11703	
11704	   return SCIP_OKAY;
11705	}
11706	
11707	/** create cumulative constraint from conflict set */
11708	static
11709	SCIP_RETCODE createCumulativeCons(
11710	   SCIP*                 scip,               /**< SCIP data structure */
11711	   const char*           name,               /**< constraint name */
11712	   TCLIQUE_GRAPH*        tcliquegraph,       /**< conflict set graph */
11713	   int*                  cliquenodes,        /**< array storing the indecies of the nodes belonging to the clique */
11714	   int                   ncliquenodes        /**< number of nodes in the clique */
11715	   )
11716	{
11717	   SCIP_CONS* cons;
11718	   SCIP_VAR** vars;
11719	   int* durations;
11720	   int* demands;
11721	   int v;
11722	
11723	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11724	   SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11725	   SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11726	
11727	   SCIPsortInt(cliquenodes, ncliquenodes);
11728	
11729	   /* collect variables, durations, and demands */
11730	   for( v = 0; v < ncliquenodes; ++v )
11731	   {
11732	      durations[v] = tcliquegraph->durations[cliquenodes[v]];
11733	      assert(durations[v] > 0);
11734	      demands[v] = 1;
11735	      vars[v] = tcliquegraph->vars[cliquenodes[v]];
11736	   }
11737	
11738	   /* create (unary) cumulative constraint */
11739	   SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11740	         FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
11741	
11742	   SCIP_CALL( SCIPaddCons(scip, cons) );
11743	   SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11744	
11745	   /* free buffers */
11746	   SCIPfreeBufferArray(scip, &demands);
11747	   SCIPfreeBufferArray(scip, &durations);
11748	   SCIPfreeBufferArray(scip, &vars);
11749	
11750	   return SCIP_OKAY;
11751	}
11752	
11753	/** search for cumulative constrainst */
11754	static
11755	SCIP_RETCODE findCumulativeConss(
11756	   SCIP*                 scip,               /**< SCIP data structure */
11757	   TCLIQUE_GRAPH*        tcliquegraph,       /**< conflict set graph */
11758	   int*                  naddconss           /**< pointer to store the number of added constraints */
11759	   )
11760	{
11761	   TCLIQUE_STATUS tcliquestatus;
11762	   SCIP_Bool* precedencerow;
11763	   SCIP_Bool* precedencecol;
11764	   SCIP_Bool* demandrow;
11765	   SCIP_Bool* demandcol;
11766	   SCIP_HASHTABLE* covered;
11767	   int* cliquenodes;
11768	   int ncliquenodes;
11769	   int cliqueweight;
11770	   int ntreenodes;
11771	   int nnodes;
11772	   int nconss;
11773	   int v;
11774	
11775	   nnodes = tcliquegraph->nnodes;
11776	   nconss = 0;
11777	
11778	   /* initialize the weight of each job with its duration */
11779	   for( v = 0; v < nnodes; ++v )
11780	   {
11781	      tcliquegraph->weights[v] = tcliquegraph->durations[v];
11782	   }
11783	
11784	   SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11785	   SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11786	   SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11787	   SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11788	   SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11789	
11790	   /* create a hash table to store all start time variables which are already covered by at least one clique */
11791	   SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11792	         SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11793	
11794	   /* for each variables/job we are ... */
11795	   for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11796	   {
11797	      char name[SCIP_MAXSTRLEN];
11798	      int c;
11799	
11800	      /* jobs with zero durations are skipped */
11801	      if( tcliquegraph->durations[v] == 0 )
11802	         continue;
11803	
11804	      /* check if the start time variable is already covered by at least one clique */
11805	      if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11806	         continue;
11807	
11808	      SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11809	
11810	      /* temporarily remove the connection via the precedence graph */
11811	      for( c = 0; c < nnodes; ++c )
11812	      {
11813	         precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11814	         precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11815	
11816	         demandrow[c] = tcliquegraph->demandmatrix[v][c];
11817	         demandcol[c] = tcliquegraph->demandmatrix[c][v];
11818	
11819	#if 0
11820	         if( precedencerow[c] || precedencecol[c] )
11821	         {
11822	            tcliquegraph->demandmatrix[v][c] = FALSE;
11823	            tcliquegraph->demandmatrix[c][v] = FALSE;
11824	         }
11825	#endif
11826	
11827	         tcliquegraph->precedencematrix[c][v] = FALSE;
11828	         tcliquegraph->precedencematrix[v][c] = FALSE;
11829	      }
11830	
11831	      /* find (heuristically) maximum cliques which includes node v */
11832	      tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11833	         tcliquegraph, tcliqueNewsolClique, NULL,
11834	         cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11835	         10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11836	
11837	      SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11838	
11839	      if( ncliquenodes == 1 )
11840	         continue;
11841	
11842	      /* construct constraint name */
11843	      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11844	
11845	      SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11846	      nconss++;
11847	
11848	      /* all start time variable to covered hash table */
11849	      for( c = 0; c < ncliquenodes; ++c )
11850	      {
11851	         SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11852	      }
11853	
11854	      /* copy the precedence relations back */
11855	      for( c = 0; c < nnodes; ++c )
11856	      {
11857	         tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11858	         tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11859	
11860	         tcliquegraph->demandmatrix[v][c] = demandrow[c];
11861	         tcliquegraph->demandmatrix[c][v] = demandcol[c];
11862	      }
11863	   }
11864	
11865	   SCIPhashtableFree(&covered);
11866	
11867	   SCIPfreeBufferArray(scip, &demandcol);
11868	   SCIPfreeBufferArray(scip, &demandrow);
11869	   SCIPfreeBufferArray(scip, &precedencecol);
11870	   SCIPfreeBufferArray(scip, &precedencerow);
11871	   SCIPfreeBufferArray(scip, &cliquenodes);
11872	
11873	   (*naddconss) += nconss;
11874	
11875	   /* for the statistic we count the number added disjunctive constraints */
11876	   SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11877	
11878	   return SCIP_OKAY;
11879	}
11880	
11881	/** create precedence constraint (as variable bound constraint */
11882	static
11883	SCIP_RETCODE createPrecedenceCons(
11884	   SCIP*                 scip,               /**< SCIP data structure */
11885	   const char*           name,               /**< constraint name */
11886	   SCIP_VAR*             var,                /**< variable x that has variable bound */
11887	   SCIP_VAR*             vbdvar,             /**< binary, integer or implicit integer bounding variable y */
11888	   int                   distance            /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11889	   )
11890	{
11891	   SCIP_CONS* cons;
11892	
11893	   /* create variable bound constraint */
11894	   SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11895	         TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
11896	
11897	   SCIPdebugPrintCons(scip, cons, NULL);
11898	
11899	   /* add constraint to problem and release it */
11900	   SCIP_CALL( SCIPaddCons(scip, cons) );
11901	   SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11902	
11903	   return SCIP_OKAY;
11904	}
11905	
11906	/** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11907	static
11908	SCIP_RETCODE computeMinDistance(
11909	   SCIP*                 scip,               /**< SCIP data structure */
11910	   TCLIQUE_GRAPH*        tcliquegraph,       /**< conflict set graph */
11911	   int                   source,             /**< index of the source node */
11912	   int                   sink,               /**< index of the sink node */
11913	   int*                  naddconss           /**< pointer to store the number of added constraints */
11914	   )
11915	{
11916	   TCLIQUE_WEIGHT cliqueweight;
11917	   TCLIQUE_STATUS tcliquestatus;
11918	   SCIP_VAR** vars;
11919	   int* cliquenodes;
11920	   int nnodes;
11921	   int lct;
11922	   int est;
11923	   int i;
11924	
11925	   int ntreenodes;
11926	   int ncliquenodes;
11927	
11928	   /* check if source and sink are connencted */
11929	   if( !tcliquegraph->precedencematrix[source][sink] )
11930	      return SCIP_OKAY;
11931	
11932	   nnodes = tcliquegraph->nnodes;
11933	   vars = tcliquegraph->vars;
11934	
11935	   /* reset the weights to zero */
11936	   BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11937	
11938	   /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11939	   lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11940	   est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11941	
11942	   /* weight all jobs which run for sure between source and sink with their duration */
11943	   for( i = 0; i < nnodes; ++i )
11944	   {
11945	      SCIP_VAR* var;
11946	      int duration;
11947	
11948	      var = vars[i];
11949	      assert(var != NULL);
11950	
11951	      duration = tcliquegraph->durations[i];
11952	
11953	      if( i == source || i == sink )
11954	      {
11955	         /* source and sink are not weighted */
11956	         tcliquegraph->weights[i] = 0;
11957	      }
11958	      else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11959	      {
11960	         /* job i runs after source and before sink */
11961	         tcliquegraph->weights[i] = duration;
11962	      }
11963	      else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11964	         && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11965	      {
11966	         /* job i run in between due the bounds of the start time variables */
11967	         tcliquegraph->weights[i] = duration;
11968	      }
11969	      else
11970	         tcliquegraph->weights[i] = 0;
11971	   }
11972	
11973	   SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11974	
11975	   /* find (heuristically) maximum cliques */
11976	   tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11977	      tcliquegraph, tcliqueNewsolClique, NULL,
11978	      cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11979	      10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11980	
11981	   if( ncliquenodes > 1 )
11982	   {
11983	      char name[SCIP_MAXSTRLEN];
11984	      int distance;
11985	
11986	      /* construct constraint name */
11987	      (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11988	
11989	      /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11990	       * duration of the source job
11991	       */
11992	      distance = cliqueweight + tcliquegraph->durations[source];
11993	
11994	      SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11995	      (*naddconss)++;
11996	   }
11997	
11998	   SCIPfreeBufferArray(scip, &cliquenodes);
11999	
12000	   return SCIP_OKAY;
12001	}
12002	
12003	/** search for precedence constraints
12004	 *
12005	 *  for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
12006	 *  corresponding two jobs
12007	 */
12008	static
12009	SCIP_RETCODE findPrecedenceConss(
12010	   SCIP*                 scip,               /**< SCIP data structure */
12011	   TCLIQUE_GRAPH*        tcliquegraph,       /**< conflict set graph */
12012	   int*                  naddconss           /**< pointer to store the number of added constraints */
12013	   )
12014	{
12015	   int* sources;
12016	   int* sinks;
12017	   int nconss;
12018	   int nnodes;
12019	   int nsources;
12020	   int nsinks;
12021	   int i;
12022	
12023	   nnodes = tcliquegraph->nnodes;
12024	   nconss = 0;
12025	
12026	   nsources = 0;
12027	   nsinks = 0;
12028	
12029	   SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
12030	   SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
12031	
12032	   /* first collect all sources and sinks */
12033	   for( i = 0; i < nnodes; ++i )
12034	   {
12035	      if( tcliquegraph->ninarcs[i] == 0 )
12036	       {
12037	          sources[nsources] = i;
12038	          nsources++;
12039	       }
12040	
12041	      if( tcliquegraph->ninarcs[i] == 0 )
12042	       {
12043	          sinks[nsinks] = i;
12044	          nsinks++;
12045	       }
12046	   }
12047	
12048	   /* compute for each node a minimum distance to each sources and each sink */
12049	   for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12050	   {
12051	      int j;
12052	
12053	      for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12054	      {
12055	         SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12056	      }
12057	
12058	      for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12059	      {
12060	         SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12061	      }
12062	   }
12063	
12064	   (*naddconss) += nconss;
12065	
12066	   /* for the statistic we count the number added variable constraints */
12067	   SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12068	
12069	   SCIPfreeBufferArray(scip, &sinks);
12070	   SCIPfreeBufferArray(scip, &sources);
12071	
12072	   return SCIP_OKAY;
12073	}
12074	
12075	/** initialize the assumed durations for each variable */
12076	static
12077	SCIP_RETCODE initializeDurations(
12078	   SCIP*                 scip,               /**< SCIP data structure */
12079	   TCLIQUE_GRAPH*        tcliquegraph,       /**< the incompatibility graph */
12080	   SCIP_CONS**           conss,              /**< cumulative constraints */
12081	   int                   nconss              /**< number of cumulative constraints */
12082	   )
12083	{
12084	   int c;
12085	
12086	   /* use the cumulative structure to define the duration we are using for each job */
12087	   for( c = 0; c < nconss; ++c )
12088	   {
12089	      SCIP_CONSDATA* consdata;
12090	      SCIP_VAR** vars;
12091	      int nvars;
12092	      int v;
12093	
12094	      consdata = SCIPconsGetData(conss[c]);
12095	      assert(consdata != NULL);
12096	
12097	      vars = consdata->vars;
12098	      nvars = consdata->nvars;
12099	
12100	      for( v = 0; v < nvars; ++v )
12101	      {
12102	         int idx;
12103	
12104	         SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12105	         assert(idx >= 0);
12106	
12107	         /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12108	          *       constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12109	          *       general this is not the case. Therefore, the question would be which duration should be used?
12110	          */
12111	         tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12112	         assert(tcliquegraph->durations[idx] > 0);
12113	      }
12114	   }
12115	
12116	   return SCIP_OKAY;
12117	}
12118	
12119	/** create tclique graph */
12120	static
12121	SCIP_RETCODE createTcliqueGraph(
12122	   SCIP*                 scip,               /**< SCIP data structure */
12123	   TCLIQUE_GRAPH**       tcliquegraph        /**< reference to the incompatibility graph */
12124	   )
12125	{
12126	   SCIP_VAR** vars;
12127	   SCIP_HASHMAP* varmap;
12128	   SCIP_Bool** precedencematrix;
12129	   SCIP_Bool** demandmatrix;
12130	   int* ninarcs;
12131	   int* noutarcs;
12132	   int* durations;
12133	   int* weights;
12134	   int nvars;
12135	   int v;
12136	
12137	   vars = SCIPgetVars(scip);
12138	   nvars = SCIPgetNVars(scip);
12139	
12140	   /* allocate memory for the tclique graph data structure */
12141	   SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12142	
12143	   /* create the variable mapping hash map */
12144	   SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12145	
12146	   /* each active variables get a node in the graph */
12147	   SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12148	
12149	   /* allocate memory for the projected variables bound graph and the none overlapping graph */
12150	   SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12151	   SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12152	
12153	   /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12154	   SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12155	   BMSclearMemoryArray(weights, nvars);
12156	
12157	   /* array to store the number of in arc of the precedence graph */
12158	   SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12159	   BMSclearMemoryArray(ninarcs, nvars);
12160	
12161	   /* array to store the number of out arc of the precedence graph */
12162	   SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12163	   BMSclearMemoryArray(noutarcs, nvars);
12164	
12165	   /* array to store the used duration for each node */
12166	   SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12167	   BMSclearMemoryArray(durations, nvars);
12168	
12169	   for( v = 0; v < nvars; ++v )
12170	   {
12171	      SCIP_VAR* var;
12172	
12173	      var = vars[v];
12174	      assert(var != NULL);
12175	
12176	      SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12177	      BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12178	
12179	      SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12180	      BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12181	
12182	      /* insert all active variables into the garph */
12183	      assert(SCIPvarGetProbindex(var) == v);
12184	      SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12185	   }
12186	
12187	   (*tcliquegraph)->nnodes = nvars;
12188	   (*tcliquegraph)->varmap = varmap;
12189	   (*tcliquegraph)->precedencematrix = precedencematrix;
12190	   (*tcliquegraph)->demandmatrix = demandmatrix;
12191	   (*tcliquegraph)->weights = weights;
12192	   (*tcliquegraph)->ninarcs = ninarcs;
12193	   (*tcliquegraph)->noutarcs = noutarcs;
12194	   (*tcliquegraph)->durations = durations;
12195	   (*tcliquegraph)->size = nvars;
12196	
12197	   return SCIP_OKAY;
12198	}
12199	
12200	/** frees the tclique graph */
12201	static
12202	void freeTcliqueGraph(
12203	   SCIP*                 scip,               /**< SCIP data structure */
12204	   TCLIQUE_GRAPH**       tcliquegraph        /**< reference to the incompatibility graph */
12205	   )
12206	{
12207	   int v;
12208	
12209	   for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12210	   {
12211	      SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12212	      SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12213	   }
12214	
12215	   SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12216	   SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12217	   SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12218	   SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12219	   SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12220	   SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12221	   SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12222	   SCIPhashmapFree(&(*tcliquegraph)->varmap);
12223	
12224	   SCIPfreeBuffer(scip, tcliquegraph);
12225	}
12226	
12227	/** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12228	 *  constrains (disjunctive constraint)
12229	 */
12230	static
12231	SCIP_RETCODE detectRedundantConss(
12232	   SCIP*                 scip,               /**< SCIP data structure */
12233	   SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
12234	   SCIP_CONS**           conss,              /**< array of cumulative constraints */
12235	   int                   nconss,             /**< number of cumulative constraints */
12236	   int*                  naddconss           /**< pointer to store the number of added constraints */
12237	   )
12238	{
12239	   TCLIQUE_GRAPH* tcliquegraph;
12240	
12241	   /* create tclique graph */
12242	   SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12243	
12244	   /* define for each job a duration */
12245	   SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12246	
12247	   /* constuct incompatibility graph */
12248	   SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12249	
12250	   /* search for new precedence constraints */
12251	   if( conshdlrdata->detectvarbounds )
12252	   {
12253	      SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12254	   }
12255	
12256	   /* search for new cumulative constraints */
12257	   if( conshdlrdata->detectdisjunctive )
12258	   {
12259	      SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12260	   }
12261	
12262	   /* free tclique graph data structure */
12263	   freeTcliqueGraph(scip, &tcliquegraph);
12264	
12265	   return SCIP_OKAY;
12266	}
12267	
12268	/** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12269	static
12270	void consdataCalcSignature(
12271	   SCIP_CONSDATA*        consdata            /**< cumulative constraint data */
12272	   )
12273	{
12274	   SCIP_VAR** vars;
12275	   int nvars;
12276	   int v;
12277	
12278	   if( consdata->validsignature )
12279	      return;
12280	
12281	   vars = consdata->vars;
12282	   nvars = consdata->nvars;
12283	
12284	   for( v = 0; v < nvars; ++v )
12285	   {
12286	      consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12287	   }
12288	
12289	   consdata->validsignature = TRUE;
12290	}
12291	
12292	/** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12293	static
12294	SCIP_DECL_SORTINDCOMP(consdataCompVar)
12295	{  /*lint --e{715}*/
12296	   SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12297	
12298	   assert(consdata != NULL);
12299	   assert(0 <= ind1 && ind1 < consdata->nvars);
12300	   assert(0 <= ind2 && ind2 < consdata->nvars);
12301	
12302	   return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12303	}
12304	
12305	/** run a pairwise comparison */
12306	static
12307	SCIP_RETCODE removeRedundantConss(
12308	   SCIP*                 scip,               /**< SCIP data structure */
12309	   SCIP_CONS**           conss,              /**< array of cumulative constraints */
12310	   int                   nconss,             /**< number of cumulative constraints */
12311	   int*                  ndelconss           /**< pointer to store the number of deletedconstraints */
12312	   )
12313	{
12314	   int i;
12315	   int j;
12316	
12317	   for( i = 0; i < nconss; ++i )
12318	   {
12319	      SCIP_CONSDATA* consdata0;
12320	      SCIP_CONS* cons0;
12321	
12322	      cons0 = conss[i];
12323	      assert(cons0 != NULL);
12324	
12325	      consdata0 = SCIPconsGetData(cons0);
12326	      assert(consdata0 != NULL);
12327	
12328	      consdataCalcSignature(consdata0);
12329	      assert(consdata0->validsignature);
12330	
12331	      for( j = i+1; j < nconss; ++j )
12332	      {
12333	         SCIP_CONSDATA* consdata1;
12334	         SCIP_CONS* cons1;
12335	
12336	         cons1 = conss[j];
12337	         assert(cons1 != NULL);
12338	
12339	         consdata1 = SCIPconsGetData(cons1);
12340	         assert(consdata1 != NULL);
12341	
12342	         if( consdata0->capacity != consdata1->capacity )
12343	            continue;
12344	
12345	         consdataCalcSignature(consdata1);
12346	         assert(consdata1->validsignature);
12347	
12348	         if( (consdata1->signature & (~consdata0->signature)) == 0 )
12349	         {
12350	            SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12351	            SCIPswapPointers((void**)&cons0, (void**)&cons1);
12352	            assert((consdata0->signature & (~consdata1->signature)) == 0);
12353	         }
12354	
12355	         if( (consdata0->signature & (~consdata1->signature)) == 0 )
12356	         {
12357	            int* perm0;
12358	            int* perm1;
12359	            int v0;
12360	            int v1;
12361	
12362	            if( consdata0->nvars > consdata1->nvars )
12363	               continue;
12364	
12365	            if( consdata0->hmin < consdata1->hmin )
12366	               continue;
12367	
12368	            if( consdata0->hmax > consdata1->hmax )
12369	               continue;
12370	
12371	            SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12372	            SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12373	
12374	            /* call sorting method  */
12375	            SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12376	            SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12377	
12378	            for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12379	            {
12380	               SCIP_VAR* var0;
12381	               SCIP_VAR* var1;
12382	               int idx0;
12383	               int idx1;
12384	               int comp;
12385	
12386	               idx0 = perm0[v0];
12387	               idx1 = perm1[v1];
12388	
12389	               var0 = consdata0->vars[idx0];
12390	
12391	               var1 = consdata1->vars[idx1];
12392	
12393	               comp = SCIPvarCompare(var0, var1);
12394	
12395	               if( comp == 0 )
12396	               {
12397	                  int duration0;
12398	                  int duration1;
12399	                  int demand0;
12400	                  int demand1;
12401	
12402	                  demand0 = consdata0->demands[idx0];
12403	                  duration0 = consdata0->durations[idx0];
12404	
12405	                  demand1 = consdata1->demands[idx1];
12406	                  duration1 = consdata1->durations[idx1];
12407	
12408	                  if( demand0 != demand1 )
12409	                     break;
12410	
12411	                  if( duration0 != duration1 )
12412	                     break;
12413	
12414	                  v0++;
12415	                  v1++;
12416	               }
12417	               else if( comp > 0 )
12418	                  v1++;
12419	               else
12420	                  break;
12421	            }
12422	
12423	            if( v0 == consdata0->nvars )
12424	            {
12425	               if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12426	               {
12427	                  initializeLocks(consdata1, TRUE);
12428	               }
12429	
12430	               /* coverity[swapped_arguments] */
12431	               SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12432	
12433	               SCIP_CALL( SCIPdelCons(scip, cons0) );
12434	               (*ndelconss)++;
12435	            }
12436	
12437	            SCIPfreeBufferArray(scip, &perm1);
12438	            SCIPfreeBufferArray(scip, &perm0);
12439	         }
12440	      }
12441	   }
12442	
12443	   return SCIP_OKAY;
12444	}
12445	
12446	/** strengthen the variable bounds using the cumulative condition */
12447	static
12448	SCIP_RETCODE strengthenVarbounds(
12449	   SCIP*                 scip,               /**< SCIP data structure */
12450	   SCIP_CONS*            cons,               /**< constraint to propagate */
12451	   int*                  nchgbds,            /**< pointer to store the number of changed bounds */
12452	   int*                  naddconss           /**< pointer to store the number of added constraints */
12453	   )
12454	{
12455	   SCIP_CONSDATA* consdata;
12456	   SCIP_VAR** vars;
12457	   int* durations;
12458	   int* demands;
12459	   int capacity;
12460	   int nvars;
12461	   int nconss;
12462	   int i;
12463	
12464	   consdata = SCIPconsGetData(cons);
12465	   assert(consdata != NULL);
12466	
12467	   /* check if the variable bounds got already strengthen by the cumulative constraint */
12468	   if( consdata->varbounds )
12469	      return SCIP_OKAY;
12470	
12471	   vars = consdata->vars;
12472	   durations = consdata->durations;
12473	   demands = consdata->demands;
12474	   capacity = consdata->capacity;
12475	   nvars = consdata->nvars;
12476	
12477	   nconss = 0;
12478	
12479	   for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12480	   {
12481	      SCIP_VAR** vbdvars;
12482	      SCIP_VAR* var;
12483	      SCIP_Real* vbdcoefs;
12484	      SCIP_Real* vbdconsts;
12485	      int nvbdvars;
12486	      int b;
12487	      int j;
12488	
12489	      var = consdata->vars[i];
12490	      assert(var != NULL);
12491	
12492	      vbdvars = SCIPvarGetVlbVars(var);
12493	      vbdcoefs = SCIPvarGetVlbCoefs(var);
12494	      vbdconsts = SCIPvarGetVlbConstants(var);
12495	      nvbdvars = SCIPvarGetNVlbs(var);
12496	
12497	      for( b = 0; b < nvbdvars; ++b )
12498	      {
12499	         if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12500	         {
12501	            if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12502	            {
12503	               for( j = 0; j < nvars; ++j )
12504	               {
12505	                  if( vars[j] == vbdvars[b] )
12506	                     break;
12507	               }
12508	               if( j == nvars )
12509	                  continue;
12510	
12511	               if( demands[i] +  demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12512	               {
12513	                  SCIP_Bool infeasible;
12514	                  char name[SCIP_MAXSTRLEN];
12515	                  int nlocalbdchgs;
12516	
12517	                  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12518	
12519	                  /* construct constraint name */
12520	                  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12521	
12522	                  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12523	                  nconss++;
12524	
12525	                  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12526	                  assert(!infeasible);
12527	
12528	                  (*nchgbds) += nlocalbdchgs;
12529	               }
12530	            }
12531	         }
12532	      }
12533	   }
12534	
12535	   (*naddconss) += nconss;
12536	
12537	   consdata->varbounds = TRUE;
12538	
12539	   return SCIP_OKAY;
12540	}
12541	
12542	/** helper function to enforce constraints */
12543	static
12544	SCIP_RETCODE enforceConstraint(
12545	   SCIP*                 scip,               /**< SCIP data structure */
12546	   SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
12547	   SCIP_CONS**           conss,              /**< constraints to process */
12548	   int                   nconss,             /**< number of constraints */
12549	   int                   nusefulconss,       /**< number of useful (non-obsolete) constraints to process */
12550	   SCIP_SOL*             sol,                /**< solution to enforce (NULL for the LP solution) */
12551	   SCIP_Bool             solinfeasible,      /**< was the solution already declared infeasible by a constraint handler? */
12552	   SCIP_RESULT*          result              /**< pointer to store the result of the enforcing call */
12553	   )
12554	{
12555	   SCIP_CONSHDLRDATA* conshdlrdata;
12556	
12557	   assert(conshdlr != NULL);
12558	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12559	   assert(nconss == 0 || conss != NULL);
12560	   assert(result != NULL);
12561	
12562	   if( solinfeasible )
12563	   {
12564	      *result = SCIP_INFEASIBLE;
12565	      return SCIP_OKAY;
12566	   }
12567	
12568	   SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12569	         sol == NULL ? "LP" : "relaxation");
12570	
12571	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12572	   assert(conshdlrdata != NULL);
12573	
12574	   (*result) = SCIP_FEASIBLE;
12575	
12576	   if( conshdlrdata->usebinvars )
12577	   {
12578	      SCIP_Bool separated;
12579	      SCIP_Bool cutoff;
12580	      int c;
12581	
12582	      separated = FALSE;
12583	
12584	      /* first check if a constraints is violated */
12585	      for( c = 0; c < nusefulconss; ++c )
12586	      {
12587	         SCIP_CONS* cons;
12588	         SCIP_Bool violated;
12589	
12590	         cons = conss[c];
12591	         assert(cons != NULL);
12592	
12593	         SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12594	
12595	         if( !violated )
12596	            continue;
12597	
12598	         SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12599	         if ( cutoff )
12600	         {
12601	            *result = SCIP_CUTOFF;
12602	            return SCIP_OKAY;
12603	         }
12604	      }
12605	
12606	      for( ; c < nconss && !separated; ++c )
12607	      {
12608	         SCIP_CONS* cons;
12609	         SCIP_Bool violated;
12610	
12611	         cons = conss[c];
12612	         assert(cons != NULL);
12613	
12614	         SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12615	
12616	         if( !violated )
12617	            continue;
12618	
12619	         SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12620	         if ( cutoff )
12621	         {
12622	            *result = SCIP_CUTOFF;
12623	            return SCIP_OKAY;
12624	         }
12625	      }
12626	
12627	      if( separated )
12628	         (*result) = SCIP_SEPARATED;
12629	   }
12630	   else
12631	   {
12632	      SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12633	   }
12634	
12635	   return SCIP_OKAY;
12636	}
12637	
12638	/**@} */
12639	
12640	
12641	/**@name Callback methods of constraint handler
12642	 *
12643	 * @{
12644	 */
12645	
12646	/** copy method for constraint handler plugins (called when SCIP copies plugins) */
12647	static
12648	SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12649	{  /*lint --e{715}*/
12650	   assert(scip != NULL);
12651	   assert(conshdlr != NULL);
12652	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12653	
12654	   /* call inclusion method of constraint handler */
12655	   SCIP_CALL( SCIPincludeConshdlrCumulative(scip) );
12656	
12657	   SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->iscopy = TRUE );
12658	
12659	   *valid = TRUE;
12660	
12661	   return SCIP_OKAY;
12662	}
12663	
12664	/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12665	static
12666	SCIP_DECL_CONSFREE(consFreeCumulative)
12667	{  /*lint --e{715}*/
12668	   SCIP_CONSHDLRDATA* conshdlrdata;
12669	
12670	   assert(conshdlr != NULL);
12671	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12672	
12673	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12674	   assert(conshdlrdata != NULL);
12675	
12676	#ifdef SCIP_STATISTIC
12677	   if( !conshdlrdata->iscopy )
12678	   {
12679	      /* statisitc output if SCIP_STATISTIC is defined */
12680	      SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12681	         conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12682	      SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12683	         conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12684	      SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12685	      conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12686	   }
12687	#endif
12688	
12689	   conshdlrdataFree(scip, &conshdlrdata);
12690	
12691	   SCIPconshdlrSetData(conshdlr, NULL);
12692	
12693	   return SCIP_OKAY;
12694	}
12695	
12696	
12697	/** presolving initialization method of constraint handler (called when presolving is about to begin) */
12698	static
12699	SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12700	{  /*lint --e{715}*/
12701	   SCIP_CONSHDLRDATA* conshdlrdata;
12702	   int c;
12703	
12704	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12705	   assert(conshdlrdata != NULL);
12706	
12707	   conshdlrdata->detectedredundant = FALSE;
12708	
12709	   for( c = 0; c < nconss; ++c )
12710	   {
12711	      /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12712	       * hmax)
12713	       */
12714	      SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12715	   }
12716	
12717	   return SCIP_OKAY;
12718	}
12719	
12720	
12721	/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12722	#ifdef SCIP_STATISTIC
12723	static
12724	SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12725	{  /*lint --e{715}*/
12726	   SCIP_CONSHDLRDATA* conshdlrdata;
12727	   int c;
12728	
12729	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12730	   assert(conshdlrdata != NULL);
12731	
12732	   for( c = 0; c < nconss; ++c )
12733	   {
12734	      SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12735	
12736	#if 0
12737	      SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12738	#endif
12739	   }
12740	
12741	   if( !conshdlrdata->iscopy )
12742	   {
12743	      SCIPstatisticPrintf("@11  added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12744	      SCIPstatisticPrintf("@22  added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12745	      SCIPstatisticPrintf("@33  irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12746	      SCIPstatisticPrintf("@44  dual %d\n", conshdlrdata->ndualfixs);
12747	      SCIPstatisticPrintf("@55  locks %d\n", conshdlrdata->nremovedlocks);
12748	      SCIPstatisticPrintf("@66  decomp %d\n", conshdlrdata->ndecomps);
12749	      SCIPstatisticPrintf("@77  allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12750	      SCIPstatisticPrintf("@88  alwaysruns %d\n", conshdlrdata->nalwaysruns);
12751	      SCIPstatisticPrintf("@99  dualbranch %d\n", conshdlrdata->ndualbranchs);
12752	   }
12753	
12754	   return SCIP_OKAY;
12755	}
12756	#endif
12757	
12758	
12759	/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12760	static
12761	SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12762	{  /*lint --e{715}*/
12763	   SCIP_CONSDATA* consdata;
12764	   int c;
12765	
12766	   assert(conshdlr != NULL);
12767	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12768	
12769	   /* release the rows of all constraints */
12770	   for( c = 0; c < nconss; ++c )
12771	   {
12772	      consdata = SCIPconsGetData(conss[c]);
12773	      assert(consdata != NULL);
12774	
12775	      /* free rows */
12776	      SCIP_CALL( consdataFreeRows(scip, &consdata) );
12777	   }
12778	
12779	   return SCIP_OKAY;
12780	}
12781	
12782	/** frees specific constraint data */
12783	static
12784	SCIP_DECL_CONSDELETE(consDeleteCumulative)
12785	{  /*lint --e{715}*/
12786	   assert(conshdlr != NULL);
12787	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12788	   assert(consdata != NULL );
12789	   assert(*consdata != NULL );
12790	
12791	   /* if constraint belongs to transformed problem space, drop bound change events on variables */
12792	   if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12793	   {
12794	      SCIP_CONSHDLRDATA* conshdlrdata;
12795	
12796	      conshdlrdata = SCIPconshdlrGetData(conshdlr);
12797	      assert(conshdlrdata != NULL);
12798	
12799	      SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12800	   }
12801	
12802	   /* free cumulative constraint data */
12803	   SCIP_CALL( consdataFree(scip, consdata) );
12804	
12805	   return SCIP_OKAY;
12806	}
12807	
12808	/** transforms constraint data into data belonging to the transformed problem */
12809	static
12810	SCIP_DECL_CONSTRANS(consTransCumulative)
12811	{  /*lint --e{715}*/
12812	   SCIP_CONSHDLRDATA* conshdlrdata;
12813	   SCIP_CONSDATA* sourcedata;
12814	   SCIP_CONSDATA* targetdata;
12815	
12816	   assert(conshdlr != NULL);
12817	   assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12818	   assert(sourcecons != NULL);
12819	   assert(targetcons != NULL);
12820	
12821	   sourcedata = SCIPconsGetData(sourcecons);
12822	   assert(sourcedata != NULL);
12823	   assert(sourcedata->demandrows == NULL);
12824	
12825	   SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12826	
12827	   /* get event handler */
12828	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12829	   assert(conshdlrdata != NULL);
12830	   assert(conshdlrdata->eventhdlr != NULL);
12831	
12832	   /* create constraint data for target constraint */
12833	   SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12834	         sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12835	         sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12836	
12837	   /* create target constraint */
12838	   SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12839	         SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12840	         SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12841	         SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12842	         SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12843	
12844	   /* catch bound change events of variables */
12845	   SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12846	
12847	   return SCIP_OKAY;
12848	}
12849	
12850	/** LP initialization method of constraint handler */
12851	static
12852	SCIP_DECL_CONSINITLP(consInitlpCumulative)
12853	{
12854	   SCIP_CONSHDLRDATA* conshdlrdata;
12855	   int c;
12856	
12857	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12858	   assert(conshdlr != NULL);
12859	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12860	   assert(conshdlrdata != NULL);
12861	
12862	   *infeasible = FALSE;
12863	
12864	   SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12865	
12866	   if( conshdlrdata->usebinvars )
12867	   {
12868	      /* add rows to LP */
12869	      for( c = 0; c < nconss && !(*infeasible); ++c )
12870	      {
12871	         assert(SCIPconsIsInitial(conss[c]));
12872	         SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12873	
12874	         if( conshdlrdata->cutsasconss )
12875	         {
12876	            SCIP_CALL( SCIPrestartSolve(scip) );
12877	         }
12878	      }
12879	   }
12880	
12881	   /**@todo if we want to use only the integer variables; only these will be in cuts
12882	    *       create some initial cuts, currently these are only separated */
12883	
12884	   return SCIP_OKAY;
12885	}
12886	
12887	/** separation method of constraint handler for LP solutions */
12888	static
12889	SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12890	{
12891	   SCIP_CONSHDLRDATA* conshdlrdata;
12892	   SCIP_Bool cutoff;
12893	   SCIP_Bool separated;
12894	   int c;
12895	
12896	   SCIPdebugMsg(scip, "consSepalpCumulative\n");
12897	
12898	   assert(conshdlr != NULL);
12899	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12900	   assert(nconss == 0 || conss != NULL);
12901	   assert(result != NULL);
12902	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12903	   assert(conshdlrdata != NULL);
12904	
12905	   SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12906	
12907	   cutoff = FALSE;
12908	   separated = FALSE;
12909	   (*result) = SCIP_DIDNOTRUN;
12910	
12911	   if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12912	      return SCIP_OKAY;
12913	
12914	   (*result) = SCIP_DIDNOTFIND;
12915	
12916	   if( conshdlrdata->usebinvars )
12917	   {
12918	      /* check all useful cumulative constraints for feasibility  */
12919	      for( c = 0; c < nusefulconss && !cutoff; ++c )
12920	      {
12921	         SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12922	      }
12923	
12924	      if( !cutoff && conshdlrdata->usecovercuts )
12925	      {
12926	         for( c = 0; c < nusefulconss; ++c )
12927	         {
12928	            SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12929	         }
12930	      }
12931	   }
12932	
12933	   if( conshdlrdata->sepaold )
12934	   {
12935	      /* separate cuts containing only integer variables */
12936	      for( c = 0; c < nusefulconss; ++c )
12937	      {
12938	         SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12939	         SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12940	      }
12941	   }
12942	
12943	   if( cutoff )
12944	      *result = SCIP_CUTOFF;
12945	   else if( separated )
12946	      *result = SCIP_SEPARATED;
12947	
12948	   return SCIP_OKAY;
12949	}
12950	
12951	/** separation method of constraint handler for arbitrary primal solutions */
12952	static
12953	SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12954	{  /*lint --e{715}*/
12955	   SCIP_CONSHDLRDATA* conshdlrdata;
12956	   SCIP_Bool cutoff;
12957	   SCIP_Bool separated;
12958	   int c;
12959	
12960	   assert(conshdlr != NULL);
12961	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12962	   assert(nconss == 0 || conss != NULL);
12963	   assert(result != NULL);
12964	
12965	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
12966	   assert(conshdlrdata != NULL);
12967	
12968	   if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12969	      return SCIP_OKAY;
12970	
12971	   SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12972	
12973	   cutoff = FALSE;
12974	   separated = FALSE;
12975	   (*result) = SCIP_DIDNOTFIND;
12976	
12977	   if( conshdlrdata->usebinvars )
12978	   {
12979	      /* check all useful cumulative constraints for feasibility  */
12980	      for( c = 0; c < nusefulconss && !cutoff; ++c )
12981	      {
12982	         SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12983	      }
12984	
12985	      if( !cutoff && conshdlrdata->usecovercuts )
12986	      {
12987	         for( c = 0; c < nusefulconss; ++c )
12988	         {
12989	            SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12990	         }
12991	      }
12992	   }
12993	   if( conshdlrdata->sepaold )
12994	   {
12995	      /* separate cuts containing only integer variables */
12996	      for( c = 0; c < nusefulconss; ++c )
12997	      {
12998	         SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12999	         SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
13000	      }
13001	   }
13002	
13003	   if( cutoff )
13004	      *result = SCIP_CUTOFF;
13005	   else if( separated )
13006	      *result = SCIP_SEPARATED;
13007	
13008	   return SCIP_OKAY;
13009	}
13010	
13011	/** constraint enforcing method of constraint handler for LP solutions */
13012	static
13013	SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
13014	{  /*lint --e{715}*/
13015	   SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
13016	
13017	   return SCIP_OKAY;
13018	}
13019	
13020	/** constraint enforcing method of constraint handler for relaxation solutions */
13021	static
13022	SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
13023	{  /*lint --e{715}*/
13024	   SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
13025	
13026	   return SCIP_OKAY;
13027	}
13028	
13029	/** constraint enforcing method of constraint handler for pseudo solutions */
13030	static
13031	SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
13032	{  /*lint --e{715}*/
13033	   SCIP_CONSHDLRDATA* conshdlrdata;
13034	
13035	   SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13036	
13037	   assert(conshdlr != NULL);
13038	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13039	   assert(nconss == 0 || conss != NULL);
13040	   assert(result != NULL);
13041	
13042	   if( objinfeasible )
13043	   {
13044	      *result = SCIP_DIDNOTRUN;
13045	      return SCIP_OKAY;
13046	   }
13047	
13048	   (*result) = SCIP_FEASIBLE;
13049	
13050	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13051	   assert(conshdlrdata != NULL);
13052	
13053	   SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13054	
13055	   return SCIP_OKAY;
13056	}
13057	
13058	/** feasibility check method of constraint handler for integral solutions */
13059	static
13060	SCIP_DECL_CONSCHECK(consCheckCumulative)
13061	{  /*lint --e{715}*/
13062	   int c;
13063	
13064	   assert(conshdlr != NULL);
13065	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13066	   assert(nconss == 0 || conss != NULL);
13067	   assert(result != NULL);
13068	
13069	   *result = SCIP_FEASIBLE;
13070	
13071	   SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13072	
13073	   for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13074	   {
13075	      SCIP_Bool violated = FALSE;
13076	
13077	      SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13078	
13079	      if( violated )
13080	         *result = SCIP_INFEASIBLE;
13081	   }
13082	
13083	   return SCIP_OKAY;
13084	}
13085	
13086	/** domain propagation method of constraint handler */
13087	static
13088	SCIP_DECL_CONSPROP(consPropCumulative)
13089	{  /*lint --e{715}*/
13090	   SCIP_CONSHDLRDATA* conshdlrdata;
13091	   SCIP_Bool cutoff;
13092	   int nchgbds;
13093	   int ndelconss;
13094	   int c;
13095	#if 0
13096	   int naggrvars = 0;
13097	#endif
13098	
13099	   SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13100	
13101	   assert(conshdlr != NULL);
13102	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13103	   assert(nconss == 0 || conss != NULL);
13104	   assert(result != NULL);
13105	
13106	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13107	   assert(conshdlrdata != NULL);
13108	
13109	   nchgbds = 0;
13110	   ndelconss = 0;
13111	   cutoff = FALSE;
13112	   (*result) = SCIP_DIDNOTRUN;
13113	
13114	   /* propgate all useful constraints */
13115	   for( c = 0; c < nusefulconss && !cutoff; ++c )
13116	   {
13117	      SCIP_CONS* cons;
13118	
13119	      cons = conss[c];
13120	      assert(cons != NULL);
13121	
13122	      if( SCIPgetDepth(scip) == 0 )
13123	      {
13124	#if 0
13125	         SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13126	               &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13127	#else
13128	         SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13129	               &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13130	#endif
13131	         if( cutoff )
13132	            break;
13133	
13134	         if( SCIPconsIsDeleted(cons) )
13135	            continue;
13136	      }
13137	
13138	      SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13139	   }
13140	
13141	   if( !cutoff && nchgbds == 0 )
13142	   {
13143	      /* propgate all other constraints */
13144	      for( c = nusefulconss; c < nconss && !cutoff; ++c )
13145	      {
13146	         SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13147	      }
13148	   }
13149	
13150	#if 0
13151	   if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13152	   {
13153	      SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13154	   }
13155	#endif
13156	
13157	   if( cutoff )
13158	   {
13159	      SCIPdebugMsg(scip, "detected infeasible\n");
13160	      *result = SCIP_CUTOFF;
13161	   }
13162	   else if( nchgbds > 0 )
13163	   {
13164	      SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13165	      *result = SCIP_REDUCEDDOM;
13166	   }
13167	   else
13168	      *result = SCIP_DIDNOTFIND;
13169	
13170	   return SCIP_OKAY;
13171	}
13172	
13173	/** presolving method of constraint handler */
13174	static
13175	SCIP_DECL_CONSPRESOL(consPresolCumulative)
13176	{  /*lint --e{715}*/
13177	   SCIP_CONSHDLRDATA* conshdlrdata;
13178	   SCIP_CONS* cons;
13179	   SCIP_Bool cutoff;
13180	   SCIP_Bool unbounded;
13181	   int oldnfixedvars;
13182	   int oldnchgbds;
13183	   int oldndelconss;
13184	   int oldnaddconss;
13185	   int oldnupgdconss;
13186	   int oldnchgsides;
13187	   int oldnchgcoefs;
13188	   int c;
13189	
13190	   assert(conshdlr != NULL);
13191	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13192	   assert(scip != NULL);
13193	   assert(result != NULL);
13194	
13195	   SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13196	
13197	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13198	   assert(conshdlrdata != NULL);
13199	
13200	   *result = SCIP_DIDNOTRUN;
13201	
13202	   oldnfixedvars = *nfixedvars;
13203	   oldnchgbds = *nchgbds;
13204	   oldnchgsides = *nchgsides;
13205	   oldnchgcoefs = *nchgcoefs;
13206	   oldnupgdconss = *nupgdconss;
13207	   oldndelconss = *ndelconss;
13208	   oldnaddconss = *naddconss;
13209	   cutoff = FALSE;
13210	   unbounded = FALSE;
13211	
13212	   /* process constraints */
13213	   for( c = 0; c < nconss && !cutoff; ++c )
13214	   {
13215	      cons = conss[c];
13216	
13217	      /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13218	       * hmax)
13219	       */
13220	      SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13221	
13222	      if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13223	      {
13224	#if 0
13225	         SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13226	               nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13227	#else
13228	         SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13229	               nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13230	#endif
13231	
13232	         if( cutoff || unbounded )
13233	            break;
13234	
13235	         if( SCIPconsIsDeleted(cons) )
13236	            continue;
13237	      }
13238	
13239	      /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13240	      if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13241	      {
13242	         SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13243	      }
13244	
13245	      /* strengthen existing variable bounds using the cumulative condition */
13246	      if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13247	      {
13248	         SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13249	      }
13250	
13251	      /* propagate cumulative constraint */
13252	      SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13253	      assert(checkDemands(scip, cons) || cutoff);
13254	   }
13255	
13256	   if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13257	   {
13258	      SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13259	   }
13260	
13261	   /* only perform the detection of variable bounds and disjunctive constraint once */
13262	   if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13263	      && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13264	      && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13265	   {
13266	      /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13267	       * propagation
13268	       */
13269	      SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13270	      conshdlrdata->detectedredundant = TRUE;
13271	   }
13272	
13273	   if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13274	   {
13275	      SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13276	   }
13277	
13278	   SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13279	      *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13280	
13281	   if( cutoff )
13282	      *result = SCIP_CUTOFF;
13283	   else if( unbounded )
13284	      *result = SCIP_UNBOUNDED;
13285	   else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13286	      || *nchgcoefs > oldnchgcoefs  || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13287	      *result = SCIP_SUCCESS;
13288	   else
13289	      *result = SCIP_DIDNOTFIND;
13290	
13291	   return SCIP_OKAY;
13292	}
13293	
13294	/** propagation conflict resolving method of constraint handler */
13295	static
13296	SCIP_DECL_CONSRESPROP(consRespropCumulative)
13297	{  /*lint --e{715}*/
13298	   SCIP_CONSHDLRDATA* conshdlrdata;
13299	   SCIP_CONSDATA* consdata;
13300	
13301	   assert(conshdlr != NULL);
13302	   assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13303	   assert(scip != NULL);
13304	   assert(result != NULL);
13305	   assert(infervar != NULL);
13306	   assert(bdchgidx != NULL);
13307	
13308	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
13309	   assert(conshdlrdata != NULL);
13310	
13311	   /* process constraint */
13312	   assert(cons != NULL);
13313	
13314	   consdata = SCIPconsGetData(cons);
13315	   assert(consdata != NULL);
13316	
13317	   SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13318	      SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13319	      SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13320	
13321	   SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13322	         consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13323	         infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13324	
13325	   return SCIP_OKAY;
13326	}
13327	
13328	/** variable rounding lock method of constraint handler */
13329	static
13330	SCIP_DECL_CONSLOCK(consLockCumulative)
13331	{  /*lint --e{715}*/
13332	   SCIP_CONSDATA* consdata;
13333	   SCIP_VAR** vars;
13334	   int v;
13335	
13336	   SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13337	
13338	   assert(scip != NULL);
13339	   assert(cons != NULL);
13340	   assert(locktype == SCIP_LOCKTYPE_MODEL);
13341	
13342	   consdata = SCIPconsGetData(cons);
13343	   assert(consdata != NULL);
13344	
13345	   vars = consdata->vars;
13346	   assert(vars != NULL);
13347	
13348	   for( v = 0; v < consdata->nvars; ++v )
13349	   {
13350	      if( consdata->downlocks[v] && consdata->uplocks[v] )
13351	      {
13352	         /* the integer start variable should not get rounded in both direction  */
13353	         SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13354	      }
13355	      else if( consdata->downlocks[v]  )
13356	      {
13357	         SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13358	      }
13359	      else if( consdata->uplocks[v] )
13360	      {
13361	         SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13362	      }
13363	   }
13364	
13365	   return SCIP_OKAY;
13366	}
13367	
13368	
13369	/** constraint display method of constraint handler */
13370	static
13371	SCIP_DECL_CONSPRINT(consPrintCumulative)
13372	{  /*lint --e{715}*/
13373	   assert(scip != NULL);
13374	   assert(conshdlr != NULL);
13375	   assert(cons != NULL);
13376	
13377	   consdataPrint(scip, SCIPconsGetData(cons), file);
13378	
13379	   return SCIP_OKAY;
13380	}
13381	
13382	/** constraint copying method of constraint handler */
13383	static
13384	SCIP_DECL_CONSCOPY(consCopyCumulative)
13385	{  /*lint --e{715}*/
13386	   SCIP_CONSDATA* sourceconsdata;
13387	   SCIP_VAR** sourcevars;
13388	   SCIP_VAR** vars;
13389	   const char* consname;
13390	
13391	   int nvars;
13392	   int v;
13393	
13394	   sourceconsdata = SCIPconsGetData(sourcecons);
13395	   assert(sourceconsdata != NULL);
13396	
13397	   /* get variables of the source constraint */
13398	   nvars = sourceconsdata->nvars;
13399	   sourcevars = sourceconsdata->vars;
13400	
13401	   (*valid) = TRUE;
13402	
13403	   if( nvars == 0 )
13404	      return SCIP_OKAY;
13405	
13406	   /* allocate buffer array */
13407	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13408	
13409	   for( v = 0; v < nvars && *valid; ++v )
13410	   {
13411	      SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13412	      assert(!(*valid) || vars[v] != NULL);
13413	   }
13414	
13415	   /* only create the target constraint, if all variables could be copied */
13416	   if( *valid )
13417	   {
13418	      if( name != NULL )
13419	         consname = name;
13420	      else
13421	         consname = SCIPconsGetName(sourcecons);
13422	
13423	      /* create a copy of the cumulative constraint */
13424	      SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13425	            sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13426	            initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13427	
13428	      /* adjust left side if the time axis if needed */
13429	      if( sourceconsdata->hmin > 0 )
13430	      {
13431	         SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13432	      }
13433	
13434	      /* adjust right  side if the time axis if needed */
13435	      if( sourceconsdata->hmax < INT_MAX )
13436	      {
13437	         SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13438	      }
13439	   }
13440	
13441	   /* free buffer array */
13442	   SCIPfreeBufferArray(scip, &vars);
13443	
13444	   return SCIP_OKAY;
13445	}
13446	
13447	
13448	/** constraint parsing method of constraint handler */
13449	static
13450	SCIP_DECL_CONSPARSE(consParseCumulative)
13451	{  /*lint --e{715}*/
13452	   SCIP_VAR** vars;
13453	   SCIP_VAR* var;
13454	   SCIP_Real value;
13455	   char strvalue[SCIP_MAXSTRLEN];
13456	   char* endptr;
13457	   int* demands;
13458	   int* durations;
13459	   int capacity;
13460	   int duration;
13461	   int demand;
13462	   int hmin;
13463	   int hmax;
13464	   int varssize;
13465	   int nvars;
13466	
13467	   SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13468	
13469	   *success = TRUE;
13470	
13471	   /* cutoff "cumulative" form the constraint string */
13472	   SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13473	   str = endptr;
13474	
13475	   varssize = 100;
13476	   nvars = 0;
13477	
13478	   /* allocate buffer array for variables */
13479	   SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13480	   SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13481	   SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13482	
13483	   do
13484	   {
13485	      SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13486	
13487	      if( var == NULL )
13488	      {
13489	         endptr = strchr(endptr, ')');
13490	
13491	         if( endptr == NULL )
13492	            *success = FALSE;
13493	         else
13494	            str = endptr;
13495	
13496	         break;
13497	      }
13498	
13499	      str = endptr;
13500	      SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13501	      duration = atoi(strvalue);
13502	      str = endptr;
13503	
13504	      SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13505	      demand = atoi(strvalue);
13506	      str = endptr;
13507	
13508	      SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13509	
13510	      vars[nvars] = var;
13511	      demands[nvars] = demand;
13512	      durations[nvars] = duration;
13513	      nvars++;
13514	   }
13515	   while( *str != ')' );
13516	
13517	   if( *success )
13518	   {
13519	      /* parse effective time window */
13520	      SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13521	      hmin = atoi(strvalue);
13522	      str = endptr;
13523	
13524	      if( SCIPparseReal(scip, str, &value, &endptr) )
13525	      {
13526	         hmax = (int)(value);
13527	         str = endptr;
13528	
13529	         /* parse capacity */
13530	         SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13531	         str = endptr;
13532	         if( SCIPparseReal(scip, str, &value, &endptr) )
13533	         {
13534	            capacity = (int)value;
13535	
13536	            /* create cumulative constraint */
13537	            SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13538	                  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13539	
13540	            SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13541	            SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13542	         }
13543	      }
13544	   }
13545	
13546	   /* free buffer arrays */
13547	   SCIPfreeBufferArray(scip, &durations);
13548	   SCIPfreeBufferArray(scip, &demands);
13549	   SCIPfreeBufferArray(scip, &vars);
13550	
13551	   return SCIP_OKAY;
13552	}
13553	
13554	
13555	/** constraint method of constraint handler which returns the variables (if possible) */
13556	static
13557	SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13558	{  /*lint --e{715}*/
13559	   SCIP_CONSDATA* consdata;
13560	
13561	   consdata = SCIPconsGetData(cons);
13562	   assert(consdata != NULL);
13563	
13564	   if( varssize < consdata->nvars )
13565	      (*success) = FALSE;
13566	   else
13567	   {
13568	      assert(vars != NULL);
13569	
13570	      BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13571	      (*success) = TRUE;
13572	   }
13573	
13574	   return SCIP_OKAY;
13575	}
13576	
13577	/** constraint method of constraint handler which returns the number of variables (if possible) */
13578	static
13579	SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13580	{  /*lint --e{715}*/
13581	   SCIP_CONSDATA* consdata;
13582	
13583	   consdata = SCIPconsGetData(cons);
13584	   assert(consdata != NULL);
13585	
13586	   (*nvars) = consdata->nvars;
13587	   (*success) = TRUE;
13588	
13589	   return SCIP_OKAY;
13590	}
13591	
13592	/**@} */
13593	
13594	/**@name Callback methods of event handler
13595	 *
13596	 * @{
13597	 */
13598	
13599	
13600	/** execution method of event handler */
13601	static
13602	SCIP_DECL_EVENTEXEC(eventExecCumulative)
13603	{  /*lint --e{715}*/
13604	   SCIP_CONSDATA* consdata;
13605	
13606	   assert(scip != NULL);
13607	   assert(eventhdlr != NULL);
13608	   assert(eventdata != NULL);
13609	   assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13610	   assert(event != NULL);
13611	
13612	   consdata = (SCIP_CONSDATA*)eventdata;
13613	   assert(consdata != NULL);
13614	
13615	   /* mark the constraint to be not propagated */
13616	   consdata->propagated = FALSE;
13617	
13618	   return SCIP_OKAY;
13619	}
13620	
13621	/**@} */
13622	
13623	/*
13624	 * constraint specific interface methods
13625	 */
13626	
13627	/** creates the handler for cumulative constraints and includes it in SCIP */
13628	SCIP_RETCODE SCIPincludeConshdlrCumulative(
13629	   SCIP*                 scip                /**< SCIP data structure */
13630	   )
13631	{
13632	   SCIP_CONSHDLRDATA* conshdlrdata;
13633	   SCIP_CONSHDLR* conshdlr;
13634	   SCIP_EVENTHDLR* eventhdlr;
13635	
13636	   /* create event handler for bound change events */
13637	   SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13638	
13639	   /* create cumulative constraint handler data */
13640	   SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13641	
13642	   /* include constraint handler */
13643	   SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
13644	         CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
13645	         consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13646	         conshdlrdata) );
13647	
13648	   assert(conshdlr != NULL);
13649	
13650	   /* set non-fundamental callbacks via specific setter functions */
13651	   SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13652	   SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13653	#ifdef SCIP_STATISTIC
13654	   SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13655	#endif
13656	   SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13657	   SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13658	   SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13659	   SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13660	   SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13661	   SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13662	   SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13663	   SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13664	         CONSHDLR_PRESOLTIMING) );
13665	   SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13666	   SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13667	         CONSHDLR_PROP_TIMING) );
13668	   SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13669	   SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13670	         CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
13671	   SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13672	   SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13673	
13674	   /* add cumulative constraint handler parameters */
13675	   SCIP_CALL( SCIPaddBoolParam(scip,
13676	         "constraints/" CONSHDLR_NAME "/ttinfer",
13677	         "should time-table (core-times) propagator be used to infer bounds?",
13678	         &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13679	   SCIP_CALL( SCIPaddBoolParam(scip,
13680	         "constraints/" CONSHDLR_NAME "/efcheck",
13681	         "should edge-finding be used to detect an overload?",
13682	         &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13683	   SCIP_CALL( SCIPaddBoolParam(scip,
13684	         "constraints/" CONSHDLR_NAME "/efinfer",
13685	         "should edge-finding be used to infer bounds?",
13686	         &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13687	   SCIP_CALL( SCIPaddBoolParam(scip,
13688	         "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13689	         &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13690	   SCIP_CALL( SCIPaddBoolParam(scip,
13691	         "constraints/" CONSHDLR_NAME "/ttefcheck",
13692	         "should time-table edge-finding be used to detect an overload?",
13693	         &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13694	   SCIP_CALL( SCIPaddBoolParam(scip,
13695	         "constraints/" CONSHDLR_NAME "/ttefinfer",
13696	         "should time-table edge-finding be used to infer bounds?",
13697	         &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13698	
13699	   SCIP_CALL( SCIPaddBoolParam(scip,
13700	         "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13701	         &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13702	   SCIP_CALL( SCIPaddBoolParam(scip,
13703	         "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13704	         &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13705	   SCIP_CALL( SCIPaddBoolParam(scip,
13706	         "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13707	         &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13708	   SCIP_CALL( SCIPaddBoolParam(scip,
13709	         "constraints/" CONSHDLR_NAME "/cutsasconss",
13710	         "should the cumulative constraint create cuts as knapsack constraints?",
13711	         &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13712	   SCIP_CALL( SCIPaddBoolParam(scip,
13713	         "constraints/" CONSHDLR_NAME "/sepaold",
13714	         "shall old sepa algo be applied?",
13715	         &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13716	
13717	   SCIP_CALL( SCIPaddBoolParam(scip,
13718	         "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13719	         &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13720	
13721	   /* presolving parameters */
13722	   SCIP_CALL( SCIPaddBoolParam(scip,
13723	         "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13724	         &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13725	   SCIP_CALL( SCIPaddBoolParam(scip,
13726	         "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13727	         &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13728	   SCIP_CALL( SCIPaddBoolParam(scip,
13729	         "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13730	         &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13731	   SCIP_CALL( SCIPaddBoolParam(scip,
13732	         "constraints/" CONSHDLR_NAME "/presolpairwise",
13733	         "should pairwise constraint comparison be performed in presolving?",
13734	         &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13735	   SCIP_CALL( SCIPaddBoolParam(scip,
13736	         "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13737	         &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13738	
13739	   SCIP_CALL( SCIPaddLongintParam(scip,
13740	         "constraints/" CONSHDLR_NAME "/maxnodes",
13741	         "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13742	         &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13743	   SCIP_CALL( SCIPaddBoolParam(scip,
13744	         "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13745	         &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13746	   SCIP_CALL( SCIPaddBoolParam(scip,
13747	         "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13748	         &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13749	
13750	   /* conflict analysis parameters */
13751	   SCIP_CALL( SCIPaddBoolParam(scip,
13752	         "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13753	         &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13754	
13755	   return SCIP_OKAY;
13756	}
13757	
13758	/** creates and captures a cumulative constraint */
13759	SCIP_RETCODE SCIPcreateConsCumulative(
13760	   SCIP*                 scip,               /**< SCIP data structure */
13761	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
13762	   const char*           name,               /**< name of constraint */
13763	   int                   nvars,              /**< number of variables (jobs) */
13764	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
13765	   int*                  durations,          /**< array containing corresponding durations */
13766	   int*                  demands,            /**< array containing corresponding demands */
13767	   int                   capacity,           /**< available cumulative capacity */
13768	   SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
13769	                                              *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13770	   SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
13771	                                              *   Usually set to TRUE. */
13772	   SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
13773	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
13774	   SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
13775	                                              *   TRUE for model constraints, FALSE for additional, redundant constraints. */
13776	   SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
13777	                                              *   Usually set to TRUE. */
13778	   SCIP_Bool             local,              /**< is constraint only valid locally?
13779	                                              *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13780	   SCIP_Bool             modifiable,         /**< is constraint modifiable (subject to column generation)?
13781	                                              *   Usually set to FALSE. In column generation applications, set to TRUE if pricing
13782	                                              *   adds coefficients to this constraint. */
13783	   SCIP_Bool             dynamic,            /**< is constraint subject to aging?
13784	                                              *   Usually set to FALSE. Set to TRUE for own cuts which
13785	                                              *   are seperated as constraints. */
13786	   SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
13787	                                              *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13788	   SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
13789	                                              *   if it may be moved to a more global node?
13790	                                              *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13791	   )
13792	{
13793	   SCIP_CONSHDLR* conshdlr;
13794	   SCIP_CONSDATA* consdata;
13795	
13796	   assert(scip != NULL);
13797	
13798	   /* find the cumulative constraint handler */
13799	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13800	   if( conshdlr == NULL )
13801	   {
13802	      SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13803	      return SCIP_PLUGINNOTFOUND;
13804	   }
13805	
13806	   SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13807	
13808	   /* create constraint data */
13809	   SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13810	
13811	   /* create constraint */
13812	   SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13813	         initial, separate, enforce, check, propagate,
13814	         local, modifiable, dynamic, removable, stickingatnode) );
13815	
13816	   if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13817	   {
13818	      SCIP_CONSHDLRDATA* conshdlrdata;
13819	
13820	      /* get event handler */
13821	      conshdlrdata = SCIPconshdlrGetData(conshdlr);
13822	      assert(conshdlrdata != NULL);
13823	      assert(conshdlrdata->eventhdlr != NULL);
13824	
13825	      /* catch bound change events of variables */
13826	      SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13827	   }
13828	
13829	   return SCIP_OKAY;
13830	}
13831	
13832	/** creates and captures a cumulative constraint
13833	 *  in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13834	 *  method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13835	 *
13836	 *  @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13837	 *
13838	 *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13839	 */
13840	SCIP_RETCODE SCIPcreateConsBasicCumulative(
13841	   SCIP*                 scip,               /**< SCIP data structure */
13842	   SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
13843	   const char*           name,               /**< name of constraint */
13844	   int                   nvars,              /**< number of variables (jobs) */
13845	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
13846	   int*                  durations,          /**< array containing corresponding durations */
13847	   int*                  demands,            /**< array containing corresponding demands */
13848	   int                   capacity            /**< available cumulative capacity */
13849	   )
13850	{
13851	   assert(scip != NULL);
13852	
13853	   SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13854	         TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13855	
13856	   return SCIP_OKAY;
13857	}
13858	
13859	/** set the left bound of the time axis to be considered (including hmin) */   /*lint -e{715}*/
13860	SCIP_RETCODE SCIPsetHminCumulative(
13861	   SCIP*                 scip,               /**< SCIP data structure */
13862	   SCIP_CONS*            cons,               /**< constraint data */
13863	   int                   hmin                /**< left bound of time axis to be considered */
13864	   )
13865	{
13866	   SCIP_CONSDATA* consdata;
13867	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13868	   {
13869	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
13870	      return SCIP_INVALIDCALL;
13871	   }
13872	
13873	   consdata = SCIPconsGetData(cons);
13874	   assert(consdata != NULL);
13875	   assert(hmin >= 0);
13876	   assert(hmin <= consdata->hmax);
13877	
13878	   consdata->hmin = hmin;
13879	
13880	   return SCIP_OKAY;
13881	}
13882	
13883	/** returns the left bound of the time axis to be considered */  /*lint -e{715}*/
13884	int SCIPgetHminCumulative(
13885	   SCIP*                 scip,               /**< SCIP data structure */
13886	   SCIP_CONS*            cons                /**< constraint */
13887	   )
13888	{
13889	   SCIP_CONSDATA* consdata;
13890	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13891	   {
13892	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
13893	      SCIPABORT();
13894	      return 0;  /*lint !e527*/
13895	   }
13896	
13897	   consdata = SCIPconsGetData(cons);
13898	   assert(consdata != NULL);
13899	
13900	   return consdata->hmin;
13901	}
13902	
13903	/** set the right bound of the time axis to be considered (not including hmax) */  /*lint -e{715}*/
13904	SCIP_RETCODE SCIPsetHmaxCumulative(
13905	   SCIP*                 scip,               /**< SCIP data structure */
13906	   SCIP_CONS*            cons,               /**< constraint data */
13907	   int                   hmax                /**< right bound of time axis to be considered */
13908	   )
13909	{
13910	   SCIP_CONSDATA* consdata;
13911	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13912	   {
13913	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
13914	      SCIPABORT();
13915	      return SCIP_INVALIDCALL; /*lint !e527*/
13916	   }
13917	
13918	   consdata = SCIPconsGetData(cons);
13919	   assert(consdata != NULL);
13920	   assert(hmax >= consdata->hmin);
13921	
13922	   consdata->hmax = hmax;
13923	
13924	   return SCIP_OKAY;
13925	}
13926	
13927	/** returns the right bound of the time axis to be considered */  /*lint -e{715}*/
13928	int SCIPgetHmaxCumulative(
13929	   SCIP*                 scip,               /**< SCIP data structure */
13930	   SCIP_CONS*            cons                /**< constraint */
13931	   )
13932	{
13933	   SCIP_CONSDATA* consdata;
13934	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13935	   {
13936	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
13937	      SCIPABORT();
13938	      return 0;  /*lint !e527*/
13939	   }
13940	
13941	   consdata = SCIPconsGetData(cons);
13942	   assert(consdata != NULL);
13943	
13944	   return consdata->hmax;
13945	}
13946	
13947	/** returns the activities of the cumulative constraint */  /*lint -e{715}*/
13948	SCIP_VAR** SCIPgetVarsCumulative(
13949	   SCIP*                 scip,               /**< SCIP data structure */
13950	   SCIP_CONS*            cons                /**< constraint data */
13951	   )
13952	{
13953	   SCIP_CONSDATA* consdata;
13954	
13955	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13956	   {
13957	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
13958	      SCIPABORT();
13959	      return NULL;  /*lint !e527*/
13960	   }
13961	
13962	   consdata = SCIPconsGetData(cons);
13963	   assert(consdata != NULL);
13964	
13965	   return consdata->vars;
13966	}
13967	
13968	/** returns the activities of the cumulative constraint */  /*lint -e{715}*/
13969	int SCIPgetNVarsCumulative(
13970	   SCIP*                 scip,               /**< SCIP data structure */
13971	   SCIP_CONS*            cons                /**< constraint data */
13972	   )
13973	{
13974	   SCIP_CONSDATA* consdata;
13975	
13976	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13977	   {
13978	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
13979	      SCIPABORT();
13980	      return -1;  /*lint !e527*/
13981	   }
13982	
13983	   consdata = SCIPconsGetData(cons);
13984	   assert(consdata != NULL);
13985	
13986	   return consdata->nvars;
13987	}
13988	
13989	/** returns the capacity of the cumulative constraint */  /*lint -e{715}*/
13990	int SCIPgetCapacityCumulative(
13991	   SCIP*                 scip,               /**< SCIP data structure */
13992	   SCIP_CONS*            cons                /**< constraint data */
13993	   )
13994	{
13995	   SCIP_CONSDATA* consdata;
13996	
13997	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13998	   {
13999	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
14000	      SCIPABORT();
14001	      return -1;  /*lint !e527*/
14002	   }
14003	
14004	   consdata = SCIPconsGetData(cons);
14005	   assert(consdata != NULL);
14006	
14007	   return consdata->capacity;
14008	}
14009	
14010	/** returns the durations of the cumulative constraint */  /*lint -e{715}*/
14011	int* SCIPgetDurationsCumulative(
14012	   SCIP*                 scip,               /**< SCIP data structure */
14013	   SCIP_CONS*            cons                /**< constraint data */
14014	   )
14015	{
14016	   SCIP_CONSDATA* consdata;
14017	
14018	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14019	   {
14020	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
14021	      SCIPABORT();
14022	      return NULL;  /*lint !e527*/
14023	   }
14024	
14025	   consdata = SCIPconsGetData(cons);
14026	   assert(consdata != NULL);
14027	
14028	   return consdata->durations;
14029	}
14030	
14031	/** returns the demands of the cumulative constraint */  /*lint -e{715}*/
14032	int* SCIPgetDemandsCumulative(
14033	   SCIP*                 scip,               /**< SCIP data structure */
14034	   SCIP_CONS*            cons                /**< constraint data */
14035	   )
14036	{
14037	   SCIP_CONSDATA* consdata;
14038	
14039	   if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14040	   {
14041	      SCIPerrorMessage("constraint is not a cumulative constraint\n");
14042	      SCIPABORT();
14043	      return NULL;  /*lint !e527*/
14044	   }
14045	
14046	   consdata = SCIPconsGetData(cons);
14047	   assert(consdata != NULL);
14048	
14049	   return consdata->demands;
14050	}
14051	
14052	/** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14053	 *  given solution is satisfied
14054	 */
14055	SCIP_RETCODE SCIPcheckCumulativeCondition(
14056	   SCIP*                 scip,               /**< SCIP data structure */
14057	   SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
14058	   int                   nvars,              /**< number of variables (jobs) */
14059	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
14060	   int*                  durations,          /**< array containing corresponding durations */
14061	   int*                  demands,            /**< array containing corresponding demands */
14062	   int                   capacity,           /**< available cumulative capacity */
14063	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
14064	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
14065	   SCIP_Bool*            violated,           /**< pointer to store if the cumulative condition is violated */
14066	   SCIP_CONS*            cons,               /**< constraint which is checked */
14067	   SCIP_Bool             printreason         /**< should the reason for the violation be printed? */
14068	   )
14069	{
14070	   assert(scip != NULL);
14071	   assert(violated != NULL);
14072	
14073	   SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14074	         violated, cons, printreason) );
14075	
14076	   return SCIP_OKAY;
14077	}
14078	
14079	/** normalize cumulative condition */  /*lint -e{715}*/
14080	SCIP_RETCODE SCIPnormalizeCumulativeCondition(
14081	   SCIP*                 scip,               /**< SCIP data structure */
14082	   int                   nvars,              /**< number of start time variables (activities) */
14083	   SCIP_VAR**            vars,               /**< array of start time variables */
14084	   int*                  durations,          /**< array of durations */
14085	   int*                  demands,            /**< array of demands */
14086	   int*                  capacity,           /**< pointer to store the changed cumulative capacity */
14087	   int*                  nchgcoefs,          /**< pointer to count total number of changed coefficients */
14088	   int*                  nchgsides           /**< pointer to count number of side changes */
14089	   )
14090	{  /*lint --e{715}*/
14091	   normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14092	
14093	   return SCIP_OKAY;
14094	}
14095	
14096	/** searches for a time point within the cumulative condition were the cumulative condition can be split */
14097	SCIP_RETCODE SCIPsplitCumulativeCondition(
14098	   SCIP*                 scip,               /**< SCIP data structure */
14099	   int                   nvars,              /**< number of variables (jobs) */
14100	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
14101	   int*                  durations,          /**< array containing corresponding durations */
14102	   int*                  demands,            /**< array containing corresponding demands */
14103	   int                   capacity,           /**< available cumulative capacity */
14104	   int*                  hmin,               /**< pointer to store the left bound of the effective horizon */
14105	   int*                  hmax,               /**< pointer to store the right bound of the effective horizon */
14106	   int*                  split               /**< point were the cumulative condition can be split */
14107	   )
14108	{
14109	   SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14110	         hmin, hmax, split) );
14111	
14112	   return SCIP_OKAY;
14113	}
14114	
14115	/** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14116	SCIP_RETCODE SCIPpresolveCumulativeCondition(
14117	   SCIP*                 scip,               /**< SCIP data structure */
14118	   int                   nvars,              /**< number of start time variables (activities) */
14119	   SCIP_VAR**            vars,               /**< array of start time variables */
14120	   int*                  durations,          /**< array of durations */
14121	   int                   hmin,               /**< left bound of time axis to be considered */
14122	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
14123	   SCIP_Bool*            downlocks,          /**< array storing if the variable has a down lock, or NULL */
14124	   SCIP_Bool*            uplocks,            /**< array storing if the variable has an up lock, or NULL */
14125	   SCIP_CONS*            cons,               /**< constraint which gets propagated, or NULL */
14126	   SCIP_Bool*            irrelevants,        /**< array mark those variables which are irrelevant for the cumulative condition */
14127	   int*                  nfixedvars,         /**< pointer to store the number of fixed variables */
14128	   int*                  nchgsides,          /**< pointer to store the number of changed sides */
14129	   SCIP_Bool*            cutoff              /**< buffer to store whether a cutoff is detected */
14130	   )
14131	{
14132	   if( nvars <= 1 )
14133	      return SCIP_OKAY;
14134	
14135	   /* presolve constraint form the earlier start time point of view */
14136	   SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14137	         irrelevants, nfixedvars, nchgsides, cutoff) );
14138	
14139	   /* presolve constraint form the latest completion time point of view */
14140	   SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14141	         irrelevants, nfixedvars, nchgsides, cutoff) );
14142	
14143	   return SCIP_OKAY;
14144	}
14145	
14146	/** propagate the given cumulative condition */
14147	SCIP_RETCODE SCIPpropCumulativeCondition(
14148	   SCIP*                 scip,               /**< SCIP data structure */
14149	   SCIP_PRESOLTIMING     presoltiming,       /**< current presolving timing */
14150	   int                   nvars,              /**< number of variables (jobs) */
14151	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
14152	   int*                  durations,          /**< array containing corresponding durations */
14153	   int*                  demands,            /**< array containing corresponding demands */
14154	   int                   capacity,           /**< available cumulative capacity */
14155	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
14156	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
14157	   SCIP_CONS*            cons,               /**< constraint which gets propagated */
14158	   int*                  nchgbds,            /**< pointer to store the number of variable bound changes */
14159	   SCIP_Bool*            initialized,        /**< was conflict analysis initialized */
14160	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14161	   SCIP_Bool*            cutoff              /**< pointer to store if the cumulative condition is violated */
14162	   )
14163	{
14164	   SCIP_CONSHDLR* conshdlr;
14165	   SCIP_CONSHDLRDATA* conshdlrdata;
14166	   SCIP_Bool redundant;
14167	
14168	   assert(scip != NULL);
14169	   assert(cons != NULL);
14170	   assert(initialized != NULL);
14171	   assert(*initialized == FALSE);
14172	   assert(cutoff != NULL);
14173	   assert(*cutoff == FALSE);
14174	
14175	   /* find the cumulative constraint handler */
14176	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14177	   if( conshdlr == NULL )
14178	   {
14179	      SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14180	      return SCIP_PLUGINNOTFOUND;
14181	   }
14182	
14183	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
14184	   assert(conshdlrdata != NULL);
14185	
14186	   redundant = FALSE;
14187	
14188	   SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14189	         nvars, vars, durations, demands, capacity,  hmin, hmax, cons,
14190	         nchgbds, &redundant, initialized, explanation, cutoff) );
14191	
14192	   return SCIP_OKAY;
14193	}
14194	
14195	/** resolve propagation w.r.t. the cumulative condition */
14196	SCIP_RETCODE SCIPrespropCumulativeCondition(
14197	   SCIP*                 scip,               /**< SCIP data structure */
14198	   int                   nvars,              /**< number of start time variables (activities) */
14199	   SCIP_VAR**            vars,               /**< array of start time variables */
14200	   int*                  durations,          /**< array of durations */
14201	   int*                  demands,            /**< array of demands */
14202	   int                   capacity,           /**< cumulative capacity */
14203	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
14204	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
14205	   SCIP_VAR*             infervar,           /**< the conflict variable whose bound change has to be resolved */
14206	   int                   inferinfo,          /**< the user information */
14207	   SCIP_BOUNDTYPE        boundtype,          /**< the type of the changed bound (lower or upper bound) */
14208	   SCIP_BDCHGIDX*        bdchgidx,           /**< the index of the bound change, representing the point of time where the change took place */
14209	   SCIP_Real             relaxedbd,          /**< the relaxed bound which is sufficient to be explained */
14210	   SCIP_Bool*            explanation,        /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14211	   SCIP_RESULT*          result              /**< pointer to store the result of the propagation conflict resolving call */
14212	   )
14213	{
14214	   SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14215	         infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14216	
14217	   return SCIP_OKAY;
14218	}
14219	
14220	/** this method visualizes the cumulative structure in GML format */
14221	SCIP_RETCODE SCIPvisualizeConsCumulative(
14222	   SCIP*                 scip,               /**< SCIP data structure */
14223	   SCIP_CONS*            cons                /**< cumulative constraint */
14224	   )
14225	{
14226	   SCIP_CONSDATA* consdata;
14227	   SCIP_HASHTABLE* vars;
14228	   FILE* file;
14229	   SCIP_VAR* var;
14230	   char filename[SCIP_MAXSTRLEN];
14231	   int nvars;
14232	   int v;
14233	
14234	   SCIP_RETCODE retcode = SCIP_OKAY;
14235	
14236	   /* open file */
14237	   (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14238	   file = fopen(filename, "w");
14239	
14240	   /* check if the file was open */
14241	   if( file == NULL )
14242	   {
14243	      SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14244	      SCIPprintSysError(filename);
14245	      return SCIP_FILECREATEERROR;
14246	   }
14247	
14248	   consdata = SCIPconsGetData(cons);
14249	   assert(consdata != NULL);
14250	
14251	   nvars = consdata->nvars;
14252	
14253	   SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14254	         SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14255	
14256	   /* create opening of the GML format */
14257	   SCIPgmlWriteOpening(file,  TRUE);
14258	
14259	   for( v = 0; v < nvars; ++v )
14260	   {
14261	      char color[SCIP_MAXSTRLEN];
14262	
14263	      var = consdata->vars[v];
14264	      assert(var != NULL);
14265	
14266	      SCIP_CALL_TERMINATE( retcode,  SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14267	
14268	      if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14269	         (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14270	      else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14271	         (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14272	      else
14273	         (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14274	
14275	      SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14276	   }
14277	
14278	   for( v = 0; v < nvars; ++v )
14279	   {
14280	      SCIP_VAR** vbdvars;
14281	      int nvbdvars;
14282	      int b;
14283	
14284	      var = consdata->vars[v];
14285	      assert(var != NULL);
14286	
14287	      vbdvars = SCIPvarGetVlbVars(var);
14288	      nvbdvars = SCIPvarGetNVlbs(var);
14289	
14290	      for( b = 0; b < nvbdvars; ++b )
14291	      {
14292	         if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14293	         {
14294	            SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14295	         }
14296	      }
14297	
14298	#if 0
14299	      vbdvars = SCIPvarGetVubVars(var);
14300	      nvbdvars = SCIPvarGetNVubs(var);
14301	
14302	      for( b = 0; b < nvbdvars; ++b )
14303	      {
14304	         if( SCIPhashtableExists(vars, vbdvars[b]) )
14305	         {
14306	            SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14307	         }
14308	      }
14309	#endif
14310	   }
14311	
14312	   /* create closing of the GML format */
14313	   SCIPgmlWriteClosing(file);
14314	TERMINATE:
14315	   /* close file */
14316	   fclose(file);
14317	
14318	   SCIPhashtableFree(&vars);
14319	
14320	   return retcode;
14321	}
14322	
14323	/** sets method to solve an individual cumulative condition */
14324	SCIP_RETCODE SCIPsetSolveCumulative(
14325	   SCIP*                 scip,               /**< SCIP data structure */
14326	   SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14327	   )
14328	{
14329	   SCIP_CONSHDLR* conshdlr;
14330	   SCIP_CONSHDLRDATA* conshdlrdata;
14331	
14332	   /* find the cumulative constraint handler */
14333	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14334	   if( conshdlr == NULL )
14335	   {
14336	      SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14337	      return SCIP_PLUGINNOTFOUND;
14338	   }
14339	
14340	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
14341	   assert(conshdlrdata != NULL);
14342	
14343	   conshdlrdata->solveCumulative = solveCumulative;
14344	
14345	   return SCIP_OKAY;
14346	}
14347	
14348	/** solves given cumulative condition as independent sub problem
14349	 *
14350	 *  @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14351	 *        solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14352	 *        solver was interrupted.
14353	 */
14354	SCIP_RETCODE SCIPsolveCumulative(
14355	   SCIP*                 scip,               /**< SCIP data structure */
14356	   int                   njobs,              /**< number of jobs (activities) */
14357	   SCIP_Real*            ests,               /**< array with the earlier start time for each job */
14358	   SCIP_Real*            lsts,               /**< array with the latest start time for each job */
14359	   SCIP_Real*            objvals,            /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14360	   int*                  durations,          /**< array of durations */
14361	   int*                  demands,            /**< array of demands */
14362	   int                   capacity,           /**< cumulative capacity */
14363	   int                   hmin,               /**< left bound of time axis to be considered (including hmin) */
14364	   int                   hmax,               /**< right bound of time axis to be considered (not including hmax) */
14365	   SCIP_Real             timelimit,          /**< time limit for solving in seconds */
14366	   SCIP_Real             memorylimit,        /**< memory limit for solving in mega bytes (MB) */
14367	   SCIP_Longint          maxnodes,           /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint  (-1: no limit) */
14368	   SCIP_Bool*            solved,             /**< pointer to store if the problem is solved (to optimality) */
14369	   SCIP_Bool*            infeasible,         /**< pointer to store if the problem is infeasible */
14370	   SCIP_Bool*            unbounded,          /**< pointer to store if the problem is unbounded */
14371	   SCIP_Bool*            error               /**< pointer to store if an error occurred */
14372	   )
14373	{
14374	   SCIP_CONSHDLR* conshdlr;
14375	   SCIP_CONSHDLRDATA* conshdlrdata;
14376	
14377	   (*solved) = TRUE;
14378	   (*infeasible) = FALSE;
14379	   (*unbounded) = FALSE;
14380	   (*error) = FALSE;
14381	
14382	   if( njobs == 0 )
14383	      return SCIP_OKAY;
14384	
14385	   /* find the cumulative constraint handler */
14386	   conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14387	   if( conshdlr == NULL )
14388	   {
14389	      SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14390	      (*error) = TRUE;
14391	      return SCIP_PLUGINNOTFOUND;
14392	   }
14393	
14394	   conshdlrdata = SCIPconshdlrGetData(conshdlr);
14395	   assert(conshdlrdata != NULL);
14396	
14397	   /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14398	   if( timelimit > 0.0 && memorylimit > 10 )
14399	   {
14400	      SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14401	            hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14402	   }
14403	
14404	   return SCIP_OKAY;
14405	}
14406	
14407	/** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14408	 *  completion time
14409	 */
14410	SCIP_RETCODE SCIPcreateWorstCaseProfile(
14411	   SCIP*                 scip,               /**< SCIP data structure */
14412	   SCIP_PROFILE*         profile,            /**< resource profile */
14413	   int                   nvars,              /**< number of variables (jobs) */
14414	   SCIP_VAR**            vars,               /**< array of integer variable which corresponds to starting times for a job */
14415	   int*                  durations,          /**< array containing corresponding durations */
14416	   int*                  demands             /**< array containing corresponding demands */
14417	   )
14418	{
14419	   SCIP_VAR* var;
14420	   SCIP_HASHMAP* addedvars;
14421	   int* copydemands;
14422	   int* perm;
14423	   int duration;
14424	   int impliedest;
14425	   int est;
14426	   int impliedlct;
14427	   int lct;
14428	   int v;
14429	
14430	   /* create hash map for variables which are added, mapping to their duration */
14431	   SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14432	
14433	   SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14434	   SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14435	
14436	   /* sort variables  w.r.t. job demands */
14437	   for( v = 0; v < nvars; ++v )
14438	   {
14439	      copydemands[v] = demands[v];
14440	      perm[v] = v;
14441	   }
14442	   SCIPsortDownIntInt(copydemands, perm, nvars);
14443	
14444	   /* add each job with its earliest start and latest completion time into the resource profile */
14445	   for( v = 0; v < nvars; ++v )
14446	   {
14447	      int idx;
14448	
14449	      idx = perm[v];
14450	      assert(idx >= 0 && idx < nvars);
14451	
14452	      var = vars[idx];
14453	      assert(var != NULL);
14454	
14455	      duration = durations[idx];
14456	      assert(duration > 0);
14457	
14458	      est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14459	      SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14460	
14461	      lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14462	      SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14463	
14464	      if( impliedest < impliedlct )
14465	      {
14466	         SCIP_Bool infeasible;
14467	         int pos;
14468	
14469	         SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14470	         assert(!infeasible);
14471	         assert(pos == -1);
14472	      }
14473	
14474	      if( est == impliedest && lct == impliedlct )
14475	      {
14476	         SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14477	      }
14478	   }
14479	
14480	   SCIPfreeBufferArray(scip, &copydemands);
14481	   SCIPfreeBufferArray(scip, &perm);
14482	
14483	   SCIPhashmapFree(&addedvars);
14484	
14485	   return SCIP_OKAY;
14486	}
14487	
14488	/** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */  /*lint -e{715}*/
14489	int SCIPcomputeHmin(
14490	   SCIP*                 scip,               /**< SCIP data structure */
14491	   SCIP_PROFILE*         profile,            /**< worst case resource profile */
14492	   int                   capacity            /**< capacity to check */
14493	   )
14494	{
14495	   int* timepoints;
14496	   int* loads;
14497	   int ntimepoints;
14498	   int t;
14499	
14500	   ntimepoints = SCIPprofileGetNTimepoints(profile);
14501	   timepoints = SCIPprofileGetTimepoints(profile);
14502	   loads = SCIPprofileGetLoads(profile);
14503	
14504	   /* find first time point which potentially violates the capacity restriction */
14505	   for( t = 0; t < ntimepoints - 1; ++t )
14506	   {
14507	      /* check if the time point exceed w.r.t. worst case profile the capacity */
14508	      if( loads[t] > capacity )
14509	      {
14510	         assert(t == 0 || loads[t-1] <= capacity);
14511	         return timepoints[t];
14512	      }
14513	   }
14514	
14515	   return INT_MAX;
14516	}
14517	
14518	/** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */  /*lint -e{715}*/
14519	int SCIPcomputeHmax(
14520	   SCIP*                 scip,               /**< SCIP data structure */
14521	   SCIP_PROFILE*         profile,            /**< worst case profile */
14522	   int                   capacity            /**< capacity to check */
14523	   )
14524	{
14525	   int* timepoints;
14526	   int* loads;
14527	   int ntimepoints;
14528	   int t;
14529	
14530	   ntimepoints = SCIPprofileGetNTimepoints(profile);
14531	   timepoints = SCIPprofileGetTimepoints(profile);
14532	   loads = SCIPprofileGetLoads(profile);
14533	
14534	   /* find last time point which potentially violates the capacity restriction */
14535	   for( t = ntimepoints - 1; t >= 0; --t )
14536	   {
14537	      /* check if at time point t the worst case resource profile  exceeds the capacity */
14538	      if( loads[t] > capacity )
14539	      {
14540	         assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14541	         return timepoints[t+1];
14542	      }
14543	   }
14544	
14545	   return INT_MIN;
14546	}
14547