Scippy

SCIP

Solving Constraint Integer Programs

cons_cumulative.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright 2002-2022 Zuse Institute Berlin */
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? */
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? */
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) */
119 /* enforcement */
120 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
122 /* conflict analysis */
123 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
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"
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;
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;
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
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
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
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
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
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
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",
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
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",
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
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
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
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
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
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
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 
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
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
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 */
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  */
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:
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:
1373  case SCIP_STATUS_TIMELIMIT:
1374  case SCIP_STATUS_MEMLIMIT:
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:
1388  case SCIP_STATUS_GAPLIMIT:
1389  case SCIP_STATUS_SOLLIMIT:
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)
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 */
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:
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:
1662  case SCIP_STATUS_TIMELIMIT:
1663  case SCIP_STATUS_MEMLIMIT:
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:
1703  case SCIP_STATUS_GAPLIMIT:
1704  case SCIP_STATUS_SOLLIMIT:
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
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
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
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
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
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 contraint 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  else
2002  {
2003  (*consdata)->vars = NULL;
2004  (*consdata)->downlocks = NULL;
2005  (*consdata)->uplocks = NULL;
2006  (*consdata)->demands = NULL;
2007  (*consdata)->durations = NULL;
2008  (*consdata)->linkingconss = NULL;
2009  }
2010 
2011  /* initialize values for running propagation algorithms efficiently */
2012  (*consdata)->resstrength1 = -1.0;
2013  (*consdata)->resstrength2 = -1.0;
2014  (*consdata)->cumfactor1 = -1.0;
2015  (*consdata)->disjfactor1 = -1.0;
2016  (*consdata)->disjfactor2 = -1.0;
2017  (*consdata)->estimatedstrength = -1.0;
2018 
2019  SCIPstatistic( (*consdata)->maxpeak = -1 );
2020 
2021  return SCIP_OKAY;
2022 }
2023 
2024 /** releases LP rows of constraint data and frees rows array */
2025 static
2027  SCIP* scip, /**< SCIP data structure */
2028  SCIP_CONSDATA** consdata /**< constraint data */
2029  )
2030 {
2031  int r;
2032 
2033  assert(consdata != NULL);
2034  assert(*consdata != NULL);
2035 
2036  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2037  {
2038  assert((*consdata)->demandrows[r] != NULL);
2039  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2040  }
2041 
2042  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2043 
2044  (*consdata)->ndemandrows = 0;
2045  (*consdata)->demandrowssize = 0;
2046 
2047  /* free rows of cover cuts */
2048  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2049  {
2050  assert((*consdata)->scoverrows[r] != NULL);
2051  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2052  }
2053 
2054  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2055 
2056  (*consdata)->nscoverrows = 0;
2057  (*consdata)->scoverrowssize = 0;
2058 
2059  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2060  {
2061  assert((*consdata)->bcoverrows[r] != NULL);
2062  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2063  }
2064 
2065  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2066 
2067  (*consdata)->nbcoverrows = 0;
2068  (*consdata)->bcoverrowssize = 0;
2069 
2070  (*consdata)->covercuts = FALSE;
2071 
2072  return SCIP_OKAY;
2073 }
2074 
2075 /** frees a cumulative constraint data */
2076 static
2078  SCIP* scip, /**< SCIP data structure */
2079  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2080  )
2081 {
2082  int varssize;
2083  int nvars;
2084 
2085  assert(consdata != NULL);
2086  assert(*consdata != NULL);
2087 
2088  nvars = (*consdata)->nvars;
2089  varssize = (*consdata)->varssize;
2090 
2091  if( varssize > 0 )
2092  {
2093  int v;
2094 
2095  /* release and free the rows */
2096  SCIP_CALL( consdataFreeRows(scip, consdata) );
2097 
2098  /* release the linking constraints if they were generated */
2099  if( (*consdata)->linkingconss != NULL )
2100  {
2101  for( v = nvars-1; v >= 0; --v )
2102  {
2103  assert((*consdata)->linkingconss[v] != NULL );
2104  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2105  }
2106 
2107  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2108  }
2109 
2110  /* free arrays */
2111  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2112  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2113  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2114  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2115  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2116  }
2117 
2118  /* free memory */
2119  SCIPfreeBlockMemory(scip, consdata);
2120 
2121  return SCIP_OKAY;
2122 }
2123 
2124 /** prints cumulative constraint to file stream */
2125 static
2126 void consdataPrint(
2127  SCIP* scip, /**< SCIP data structure */
2128  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2129  FILE* file /**< output file (or NULL for standard output) */
2130  )
2131 {
2132  int v;
2133 
2134  assert(consdata != NULL);
2135 
2136  /* print coefficients */
2137  SCIPinfoMessage( scip, file, "cumulative(");
2138 
2139  for( v = 0; v < consdata->nvars; ++v )
2140  {
2141  assert(consdata->vars[v] != NULL);
2142  if( v > 0 )
2143  SCIPinfoMessage(scip, file, ", ");
2144  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2145  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2146  consdata->durations[v], consdata->demands[v]);
2147  }
2148  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2149 }
2150 
2151 /** deletes coefficient at given position from constraint data */
2152 static
2154  SCIP* scip, /**< SCIP data structure */
2155  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2156  SCIP_CONS* cons, /**< knapsack constraint */
2157  int pos /**< position of coefficient to delete */
2158  )
2159 {
2160  SCIP_CONSHDLR* conshdlr;
2161  SCIP_CONSHDLRDATA* conshdlrdata;
2162 
2163  assert(scip != NULL);
2164  assert(consdata != NULL);
2165  assert(cons != NULL);
2166  assert(SCIPconsIsTransformed(cons));
2167  assert(!SCIPinProbing(scip));
2168 
2169  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2170  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2171 
2172  /* remove the rounding locks for the deleted variable */
2173  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2174 
2175  consdata->downlocks[pos] = FALSE;
2176  consdata->uplocks[pos] = FALSE;
2177 
2178  if( consdata->linkingconss != NULL )
2179  {
2180  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2181  }
2182 
2183  /* get event handler */
2184  conshdlr = SCIPconsGetHdlr(cons);
2185  assert(conshdlr != NULL);
2186  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2187  assert(conshdlrdata != NULL);
2188  assert(conshdlrdata->eventhdlr != NULL);
2189 
2190  /* drop events */
2191  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2192 
2193  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2194  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2195 
2196  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2197  * position
2198  */
2199  if( pos != consdata->nvars - 1 )
2200  {
2201  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2202  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2203  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2204  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2205  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2206 
2207  if( consdata->linkingconss != NULL )
2208  {
2209  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2210  }
2211  }
2212 
2213  consdata->nvars--;
2214  consdata->validsignature = FALSE;
2215  consdata->normalized = FALSE;
2216 
2217  return SCIP_OKAY;
2218 }
2219 
2220 /** collect linking constraints for each integer variable */
2221 static
2223  SCIP* scip, /**< SCIP data structure */
2224  SCIP_CONSDATA* consdata /**< pointer to consdata */
2225  )
2226 {
2227  int nvars;
2228  int v;
2229 
2230  assert(scip != NULL);
2231  assert(consdata != NULL);
2232 
2233  nvars = consdata->nvars;
2234  assert(nvars > 0);
2235  assert(consdata->linkingconss == NULL);
2236 
2237  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2238 
2239  for( v = 0; v < nvars; ++v )
2240  {
2241  SCIP_CONS* cons;
2242  SCIP_VAR* var;
2243 
2244  var = consdata->vars[v];
2245  assert(var != NULL);
2246 
2247  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2248 
2249  /* create linking constraint if it does not exist yet */
2250  if( !SCIPexistsConsLinking(scip, var) )
2251  {
2252  char name[SCIP_MAXSTRLEN];
2253 
2254  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2255 
2256  /* creates and captures an linking constraint */
2257  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2258  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2259  SCIP_CALL( SCIPaddCons(scip, cons) );
2260  consdata->linkingconss[v] = cons;
2261  }
2262  else
2263  {
2264  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2265  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2266  }
2267 
2268  assert(SCIPexistsConsLinking(scip, var));
2269  assert(consdata->linkingconss[v] != NULL);
2270  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2271  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2272  }
2273 
2274  return SCIP_OKAY;
2275 }
2276 
2277 /**@} */
2278 
2279 
2280 /**@name Check methods
2281  *
2282  * @{
2283  */
2284 
2285 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2286  * given solution is satisfied
2287  */
2288 static
2290  SCIP* scip, /**< SCIP data structure */
2291  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2292  int nvars, /**< number of variables (jobs) */
2293  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2294  int* durations, /**< array containing corresponding durations */
2295  int* demands, /**< array containing corresponding demands */
2296  int capacity, /**< available cumulative capacity */
2297  int hmin, /**< left bound of time axis to be considered (including hmin) */
2298  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2299  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2300  SCIP_CONS* cons, /**< constraint which is checked */
2301  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2302  )
2303 {
2304  int* startsolvalues; /* stores when each job is starting */
2305  int* endsolvalues; /* stores when each job ends */
2306  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2307  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2308 
2309  int freecapacity;
2310  int curtime; /* point in time which we are just checking */
2311  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2312  int j;
2313 
2314  SCIP_Real absviol;
2315  SCIP_Real relviol;
2316 
2317  assert(scip != NULL);
2318  assert(violated != NULL);
2319 
2320  (*violated) = FALSE;
2321 
2322  if( nvars == 0 )
2323  return SCIP_OKAY;
2324 
2325  assert(vars != NULL);
2326  assert(demands != NULL);
2327  assert(durations != NULL);
2328 
2329  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2330  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2331  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2332  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2333  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2334 
2335  /* assign variables, start and endpoints to arrays */
2336  for ( j = 0; j < nvars; ++j )
2337  {
2338  int solvalue;
2339 
2340  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2341  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2342 
2343  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2344 
2345  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2346  * jobs which start before hmin to hmin
2347  */
2348  startsolvalues[j] = MAX(solvalue, hmin);
2349  startindices[j] = j;
2350 
2351  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2352  endindices[j] = j;
2353  }
2354 
2355  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2356  * corresponding indices in the same way)
2357  */
2358  SCIPsortIntInt(startsolvalues, startindices, nvars);
2359  SCIPsortIntInt(endsolvalues, endindices, nvars);
2360 
2361  endindex = 0;
2362  freecapacity = capacity;
2363  absviol = 0.0;
2364  relviol = 0.0;
2365 
2366  /* check each start point of a job whether the capacity is kept or not */
2367  for( j = 0; j < nvars; ++j )
2368  {
2369  /* only check intervals [hmin,hmax) */
2370  curtime = startsolvalues[j];
2371 
2372  if( curtime >= hmax )
2373  break;
2374 
2375  /* subtract all capacity needed up to this point */
2376  freecapacity -= demands[startindices[j]];
2377  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2378  {
2379  j++;
2380  freecapacity -= demands[startindices[j]];
2381  }
2382 
2383  /* free all capacity usages of jobs that are no longer running */
2384  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2385  {
2386  freecapacity += demands[endindices[endindex]];
2387  ++endindex;
2388  }
2389  assert(freecapacity <= capacity);
2390 
2391  /* update absolute and relative violation */
2392  if( absviol < (SCIP_Real) (-freecapacity) )
2393  {
2394  absviol = -freecapacity;
2395  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2396  }
2397 
2398  /* check freecapacity to be smaller than zero */
2399  if( freecapacity < 0 && curtime >= hmin )
2400  {
2401  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2402  (*violated) = TRUE;
2403 
2404  if( printreason )
2405  {
2406  int i;
2407 
2408  /* first state the violated constraints */
2409  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2410 
2411  /* second state the reason */
2412  SCIPinfoMessage(scip, NULL,
2413  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2414  curtime, capacity, capacity - freecapacity);
2415 
2416  for( i = 0; i <= j; ++i )
2417  {
2418  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2419  {
2420  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2421  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2422  demands[startindices[i]]);
2423  }
2424  }
2425  }
2426  break;
2427  }
2428  } /*lint --e{850}*/
2429 
2430  /* update constraint violation in solution */
2431  if( sol != NULL )
2432  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2433 
2434  /* free all buffer arrays */
2435  SCIPfreeBufferArray(scip, &endindices);
2436  SCIPfreeBufferArray(scip, &startindices);
2437  SCIPfreeBufferArray(scip, &endsolvalues);
2438  SCIPfreeBufferArray(scip, &startsolvalues);
2439 
2440  return SCIP_OKAY;
2441 }
2442 
2443 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2444  * least zero or not. If not (*violated) is set to TRUE
2445  */
2446 static
2448  SCIP* scip, /**< SCIP data structure */
2449  SCIP_CONS* cons, /**< constraint to be checked */
2450  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2451  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2452  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2453  )
2454 {
2455  SCIP_CONSDATA* consdata;
2456 
2457  assert(scip != NULL);
2458  assert(cons != NULL);
2459  assert(violated != NULL);
2460 
2461  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2462 
2463  consdata = SCIPconsGetData(cons);
2464  assert(consdata != NULL);
2465 
2466  /* check the cumulative condition */
2467  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2468  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2469  violated, cons, printreason) );
2470 
2471  return SCIP_OKAY;
2472 }
2473 
2474 /**@} */
2475 
2476 /**@name Conflict analysis
2477  *
2478  * @{
2479  */
2480 
2481 /** resolves the propagation of the core time algorithm */
2482 static
2484  SCIP* scip, /**< SCIP data structure */
2485  int nvars, /**< number of start time variables (activities) */
2486  SCIP_VAR** vars, /**< array of start time variables */
2487  int* durations, /**< array of durations */
2488  int* demands, /**< array of demands */
2489  int capacity, /**< cumulative capacity */
2490  int hmin, /**< left bound of time axis to be considered (including hmin) */
2491  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2492  SCIP_VAR* infervar, /**< inference variable */
2493  int inferdemand, /**< demand of the inference variable */
2494  int inferpeak, /**< time point which causes the propagation */
2495  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2496  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2497  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2498  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2499  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2500  )
2501 {
2502  SCIP_VAR* var;
2503  SCIP_Bool* reported;
2504  int duration;
2505  int maxlst;
2506  int minect;
2507  int ect;
2508  int lst;
2509  int j;
2510 
2511  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2512 
2513  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2514  SCIPvarGetName(infervar), inferdemand, inferpeak);
2515  assert(nvars > 0);
2516 
2517  /* adjusted capacity */
2518  capacity -= inferdemand;
2519  maxlst = INT_MIN;
2520  minect = INT_MAX;
2521 
2522  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2523  BMSclearMemoryArray(reported, nvars);
2524 
2525  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2526  * inference peak and those where the current conflict bounds provide a core at the inference peak
2527  */
2528  for( j = 0; j < nvars && capacity >= 0; ++j )
2529  {
2530  var = vars[j];
2531  assert(var != NULL);
2532 
2533  /* skip inference variable */
2534  if( var == infervar )
2535  continue;
2536 
2537  duration = durations[j];
2538  assert(duration > 0);
2539 
2540  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2541  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2542  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2543  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2544  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2545 
2546  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2548  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2549 
2550  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2551  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2552 
2553  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2554  * that job without adding it the explanation
2555  */
2556  if( inferpeak < ect && lst <= inferpeak )
2557  {
2558  capacity -= demands[j];
2559  reported[j] = TRUE;
2560 
2561  maxlst = MAX(maxlst, lst);
2562  minect = MIN(minect, ect);
2563  assert(maxlst < minect);
2564 
2565  if( explanation != NULL )
2566  explanation[j] = TRUE;
2567 
2568  continue;
2569  }
2570 
2571  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2572  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2573  * not part of the conflict yet we get the global bounds back.
2574  */
2575  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2576  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2577 
2578  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2579  * of that job without and collect the job as part of the explanation
2580  *
2581  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2582  */
2583  if( inferpeak < ect && lst <= inferpeak )
2584  {
2585  capacity -= demands[j];
2586  reported[j] = TRUE;
2587 
2588  maxlst = MAX(maxlst, lst);
2589  minect = MIN(minect, ect);
2590  assert(maxlst < minect);
2591 
2592  if( explanation != NULL )
2593  explanation[j] = TRUE;
2594  }
2595  }
2596 
2597  if( capacity >= 0 )
2598  {
2599  int* cands;
2600  int* canddemands;
2601  int ncands;
2602  int c;
2603 
2604  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2605  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2606  ncands = 0;
2607 
2608  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2609  for( j = 0; j < nvars; ++j )
2610  {
2611  var = vars[j];
2612  assert(var != NULL);
2613 
2614  /* skip inference variable */
2615  if( var == infervar || reported[j] )
2616  continue;
2617 
2618  duration = durations[j];
2619  assert(duration > 0);
2620 
2621  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2622  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2623  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2624  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2625  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2626 
2627  /* collect local core information */
2628  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2629  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2630 
2631  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2632  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2633  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2634 
2635  /* check if the inference peak is part of the core */
2636  if( inferpeak < ect && lst <= inferpeak )
2637  {
2638  cands[ncands] = j;
2639  canddemands[ncands] = demands[j];
2640  ncands++;
2641 
2642  capacity -= demands[j];
2643  }
2644  }
2645 
2646  /* sort candidates indices w.r.t. their demands */
2647  SCIPsortDownIntInt(canddemands, cands, ncands);
2648 
2649  assert(capacity < 0);
2650  assert(ncands > 0);
2651 
2652  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2653  while( capacity + canddemands[ncands-1] < 0 )
2654  {
2655  ncands--;
2656  capacity += canddemands[ncands];
2657  assert(ncands > 0);
2658  }
2659 
2660  /* compute the size (number of time steps) of the job cores */
2661  for( c = 0; c < ncands; ++c )
2662  {
2663  var = vars[cands[c]];
2664  assert(var != NULL);
2665 
2666  duration = durations[cands[c]];
2667 
2668  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2669  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2670 
2671  maxlst = MAX(maxlst, lst);
2672  minect = MIN(minect, ect);
2673  assert(maxlst < minect);
2674  }
2675 
2676  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2677  assert(inferpeak >= maxlst);
2678  assert(inferpeak < minect);
2679 
2680  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2681  if( relaxedpeak < inferpeak )
2682  {
2683  inferpeak = MAX(maxlst, relaxedpeak);
2684  }
2685  else if( relaxedpeak > inferpeak )
2686  {
2687  inferpeak = MIN(minect-1, relaxedpeak);
2688  }
2689  assert(inferpeak >= hmin);
2690  assert(inferpeak < hmax);
2691  assert(inferpeak >= maxlst);
2692  assert(inferpeak < minect);
2693 
2694  /* post all necessary bound changes */
2695  for( c = 0; c < ncands; ++c )
2696  {
2697  var = vars[cands[c]];
2698  assert(var != NULL);
2699 
2700  if( usebdwidening )
2701  {
2702  duration = durations[cands[c]];
2703 
2704  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2705  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2706  }
2707  else
2708  {
2709  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2710  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2711  }
2712 
2713  if( explanation != NULL )
2714  explanation[cands[c]] = TRUE;
2715  }
2716 
2717  SCIPfreeBufferArray(scip, &canddemands);
2718  SCIPfreeBufferArray(scip, &cands);
2719  }
2720 
2721  SCIPfreeBufferArray(scip, &reported);
2722 
2723  if( provedpeak != NULL )
2724  *provedpeak = inferpeak;
2725 
2726  return SCIP_OKAY;
2727 }
2728 
2729 #if 0
2730 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2731  * energy in total and for bound change is enough
2732  */
2733 static
2734 SCIP_RETCODE resolvePropagationEdgeFinding(
2735  SCIP* scip, /**< SCIP data structure */
2736  int nvars, /**< number of start time variables (activities) */
2737  SCIP_VAR** vars, /**< array of start time variables */
2738  int* durations, /**< array of durations */
2739  int hmin, /**< left bound of time axis to be considered (including hmin) */
2740  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2741  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2742  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2743  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2744  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2745  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2746  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2747  )
2748 {
2749  int est;
2750  int lct;
2751  int j;
2752 
2753  /* ???????????????????? do bound widening */
2754 
2755  assert(scip != NULL);
2756  assert(nvars > 0);
2757  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2758 
2759  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2760 
2761  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2762  {
2763  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2764  }
2765  else
2766  {
2767  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2768  }
2769 
2770  est = inferInfoGetData1(inferinfo);
2771  lct = inferInfoGetData2(inferinfo);
2772  assert(est < lct);
2773 
2774  /* collect the energies of all variables in [est_omega, lct_omega] */
2775  for( j = 0; j < nvars; ++j )
2776  {
2777  SCIP_VAR* var;
2778  SCIP_Bool left;
2779  SCIP_Bool right;
2780  int duration;
2781  int lb;
2782  int ub;
2783 
2784  var = vars[j];
2785  assert(var != NULL);
2786 
2787  if( var == infervar )
2788  {
2789  if( explanation != NULL )
2790  explanation[j] = TRUE;
2791 
2792  continue;
2793  }
2794 
2795  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2796  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2797 
2798  duration = durations[j];
2799  assert(duration > 0);
2800 
2801  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2802  * since we use adjusted jobs during the propagation
2803  */
2804  left = (est == hmin && lb + duration > hmin) || lb >= est;
2805 
2806  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2807  * since we use adjusted jobs during the propagation
2808  */
2809  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2810 
2811  /* store all jobs running in [est_omega; lct_omega] */
2812  if( left && right )
2813  {
2814  /* check if bound widening should be used */
2815  if( usebdwidening )
2816  {
2817  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2818  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2819  }
2820  else
2821  {
2822  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2823  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2824  }
2825 
2826  if( explanation != NULL )
2827  explanation[j] = TRUE;
2828  }
2829  }
2830 
2831  return SCIP_OKAY;
2832 }
2833 #endif
2834 
2835 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2836 static
2837 int computeOverlap(
2838  int begin, /**< begin of the times interval */
2839  int end, /**< end of time interval */
2840  int est, /**< earliest start time */
2841  int lst, /**< latest start time */
2842  int duration /**< duration of the job */
2843  )
2844 {
2845  int left;
2846  int right;
2847  int ect;
2848  int lct;
2849 
2850  ect = est + duration;
2851  lct = lst + duration;
2852 
2853  /* check if job runs completely within [begin,end) */
2854  if( lct <= end && est >= begin )
2855  return duration;
2856 
2857  assert(lst <= end && ect >= begin);
2858 
2859  left = ect - begin;
2860  assert(left > 0);
2861 
2862  right = end - lst;
2863  assert(right > 0);
2864 
2865  return MIN3(left, right, end - begin);
2866 }
2867 
2868 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2869  * reason
2870  *
2871  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2872  */
2873 static
2875  SCIP* scip, /**< SCIP data structure */
2876  int nvars, /**< number of start time variables (activities) */
2877  SCIP_VAR** vars, /**< array of start time variables */
2878  int* durations, /**< array of durations */
2879  int* demands, /**< array of demands */
2880  int capacity, /**< capacity of the cumulative condition */
2881  int begin, /**< begin of the time window */
2882  int end, /**< end of the time window */
2883  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2884  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2885  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2886  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2887  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2888  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2889  )
2890 {
2891  int* locenergies;
2892  int* overlaps;
2893  int* idxs;
2894 
2895  SCIP_Longint requiredenergy;
2896  int v;
2897 
2898  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2899  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2900  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2901 
2902  /* energy which needs be explained */
2903  requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2904 
2905  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2906 
2907  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2908  * takes
2909  */
2910  for( v = 0; v < nvars; ++v )
2911  {
2912  SCIP_VAR* var;
2913  int glbenergy;
2914  int duration;
2915  int demand;
2916  int est;
2917  int lst;
2918 
2919  var = vars[v];
2920  assert(var != NULL);
2921 
2922  locenergies[v] = 0;
2923  overlaps[v] = 0;
2924  idxs[v] = v;
2925 
2926  demand = demands[v];
2927  assert(demand > 0);
2928 
2929  duration = durations[v];
2930  assert(duration > 0);
2931 
2932  /* check if the variable equals the inference variable (the one which was propagated) */
2933  if( infervar == var )
2934  {
2935  int overlap;
2936  int right;
2937  int left;
2938 
2939  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2940 
2941  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2942  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2943  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2944 
2945  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2946  * which is necessary from the inference variable
2947  */
2948  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2949  {
2950  int lct;
2951 
2952  /* get the latest start time of the infer start time variable before the propagation took place */
2953  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2954 
2955  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2956  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2957  * scheduled w.r.t. its latest start time
2958  */
2959  assert(lst < end);
2960 
2961  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2962  * interval (before the propagation)
2963  */
2964  right = MIN3(end - lst, end - begin, duration);
2965 
2966  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2967  assert(right > 0);
2968 
2969  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2970  assert(begin <= lct);
2971  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2972 
2973  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2974  left = MIN(lct - begin + 1, end - begin);
2975  assert(left > 0);
2976 
2977  /* compute the minimum overlap; */
2978  overlap = MIN(left, right);
2979  assert(overlap > 0);
2980  assert(overlap <= end - begin);
2981  assert(overlap <= duration);
2982 
2983  if( usebdwidening )
2984  {
2985  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2986  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2987  }
2988  else
2989  {
2990  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2991  }
2992  }
2993  else
2994  {
2995  int ect;
2996 
2997  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2998 
2999  /* get the earliest completion time of the infer start time variable before the propagation took place */
3000  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
3001 
3002  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
3003  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
3004  * the job is scheduled w.r.t. its earliest start time
3005  */
3006  assert(ect > begin);
3007 
3008  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
3009  * interval (before the propagation)
3010  */
3011  left = MIN3(ect - begin, end - begin, duration);
3012 
3013  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
3014  assert(left > 0);
3015 
3016  est = SCIPconvertRealToInt(scip, relaxedbd);
3017  assert(end >= est);
3018  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
3019 
3020  /* compute the overlap of the job after the propagation but considering the relaxed bound */
3021  right = MIN(end - est + 1, end - begin);
3022  assert(right > 0);
3023 
3024  /* compute the minimum overlap */
3025  overlap = MIN(left, right);
3026  assert(overlap > 0);
3027  assert(overlap <= end - begin);
3028  assert(overlap <= duration);
3029 
3030  if( usebdwidening )
3031  {
3032  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3033  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3034  }
3035  else
3036  {
3037  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3038  }
3039  }
3040 
3041  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3042  requiredenergy -= (SCIP_Longint) overlap * demand;
3043 
3044  if( explanation != NULL )
3045  explanation[v] = TRUE;
3046 
3047  continue;
3048  }
3049 
3050  /* global time points */
3051  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3052  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3053 
3054  glbenergy = 0;
3055 
3056  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3057  * time window
3058  */
3059  if( est + duration > begin && lst < end )
3060  {
3061  /* evaluated global contribution */
3062  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3063 
3064  /* remove the globally available energy form the required energy */
3065  requiredenergy -= glbenergy;
3066 
3067  if( explanation != NULL )
3068  explanation[v] = TRUE;
3069  }
3070 
3071  /* local time points */
3072  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3073  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3074 
3075  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3076  * time window
3077  */
3078  if( est + duration > begin && lst < end )
3079  {
3080  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3081 
3082  /* evaluated additionally local energy contribution */
3083  locenergies[v] = overlaps[v] * demand - glbenergy;
3084  assert(locenergies[v] >= 0);
3085  }
3086  }
3087 
3088  /* sort the variable contributions w.r.t. additional local energy contributions */
3089  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3090 
3091  /* add local energy contributions until an overload is implied */
3092  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3093  {
3094  SCIP_VAR* var;
3095  int duration;
3096  int overlap;
3097  int relaxlb;
3098  int relaxub;
3099  int idx;
3100 
3101  idx = idxs[v];
3102  assert(idx >= 0 && idx < nvars);
3103 
3104  var = vars[idx];
3105  assert(var != NULL);
3106  assert(var != infervar);
3107 
3108  duration = durations[idx];
3109  assert(duration > 0);
3110 
3111  overlap = overlaps[v];
3112  assert(overlap > 0);
3113 
3114  requiredenergy -= locenergies[v];
3115 
3116  if( requiredenergy < -1 )
3117  {
3118  int demand;
3119 
3120  demand = demands[idx];
3121  assert(demand > 0);
3122 
3123  overlap += (int)((requiredenergy + 1) / demand);
3124 
3125 #ifndef NDEBUG
3126  requiredenergy += locenergies[v];
3127  requiredenergy -= (SCIP_Longint) overlap * demand;
3128  assert(requiredenergy < 0);
3129 #endif
3130  }
3131  assert(overlap > 0);
3132 
3133  relaxlb = begin - duration + overlap;
3134  relaxub = end - overlap;
3135 
3136  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3137  SCIPvarGetName(var),
3140  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3141  relaxlb, relaxub, demands[idx], duration);
3142 
3143  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3144  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3145 
3146  if( explanation != NULL )
3147  explanation[idx] = TRUE;
3148  }
3149 
3150  assert(requiredenergy < 0);
3151 
3152  SCIPfreeBufferArray(scip, &idxs);
3153  SCIPfreeBufferArray(scip, &overlaps);
3154  SCIPfreeBufferArray(scip, &locenergies);
3155 
3156  return SCIP_OKAY;
3157 }
3158 
3159 /** resolve propagation w.r.t. the cumulative condition */
3160 static
3162  SCIP* scip, /**< SCIP data structure */
3163  int nvars, /**< number of start time variables (activities) */
3164  SCIP_VAR** vars, /**< array of start time variables */
3165  int* durations, /**< array of durations */
3166  int* demands, /**< array of demands */
3167  int capacity, /**< cumulative capacity */
3168  int hmin, /**< left bound of time axis to be considered (including hmin) */
3169  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3170  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3171  INFERINFO inferinfo, /**< the user information */
3172  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3173  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3174  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3175  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3176  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3177  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3178  )
3179 {
3180  switch( inferInfoGetProprule(inferinfo) )
3181  {
3182  case PROPRULE_1_CORETIMES:
3183  {
3184  int inferdemand;
3185  int inferduration;
3186  int inferpos;
3187  int inferpeak;
3188  int relaxedpeak;
3189  int provedpeak;
3190 
3191  /* get the position of the inferred variable in the vars array */
3192  inferpos = inferInfoGetData1(inferinfo);
3193  if( inferpos >= nvars || vars[inferpos] != infervar )
3194  {
3195  /* find inference variable in constraint */
3196  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3197  {}
3198  }
3199  assert(inferpos < nvars);
3200  assert(vars[inferpos] == infervar);
3201 
3202  inferdemand = demands[inferpos];
3203  inferduration = durations[inferpos];
3204 
3205  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3206  {
3207  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3208  * the inference variable
3209  */
3210  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3211 
3212  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3213  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3214  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3215 
3216  /* get the inference peak that the time point which lead to the that propagtion */
3217  inferpeak = inferInfoGetData2(inferinfo);
3218  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3219  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3220  */
3221  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3222  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3223 
3224  /* make sure that the relaxed peak is part of the effective horizon */
3225  relaxedpeak = MIN(relaxedpeak, hmax-1);
3226 
3227  /* make sure that relaxed peak is not larger than the infer peak
3228  *
3229  * This can happen in case the variable is not an active variable!
3230  */
3231  relaxedpeak = MAX(relaxedpeak, inferpeak);
3232  assert(relaxedpeak >= inferpeak);
3233  assert(relaxedpeak >= hmin);
3234  }
3235  else
3236  {
3237  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3238 
3239  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3240  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3241  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3242 
3243  /* get the time interval where the job could not be scheduled */
3244  inferpeak = inferInfoGetData2(inferinfo);
3245  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3246  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3247  */
3248  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3249  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3250 
3251  /* make sure that the relaxed peak is part of the effective horizon */
3252  relaxedpeak = MAX(relaxedpeak, hmin);
3253 
3254  /* make sure that relaxed peak is not larger than the infer peak
3255  *
3256  * This can happen in case the variable is not an active variable!
3257  */
3258  relaxedpeak = MIN(relaxedpeak, inferpeak);
3259  assert(relaxedpeak < hmax);
3260  }
3261 
3262  /* resolves the propagation of the core time algorithm */
3263  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3264  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3265 
3266  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3267  {
3268  if( usebdwidening )
3269  {
3270  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3271  }
3272  else
3273  {
3274  /* old upper bound of variable itself is part of the explanation */
3275  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3276  }
3277  }
3278  else
3279  {
3280  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3281 
3282  if( usebdwidening )
3283  {
3284  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3285  }
3286  else
3287  {
3288  /* old lower bound of variable itself is part of the explanation */
3289  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3290  }
3291  }
3292 
3293  if( explanation != NULL )
3294  explanation[inferpos] = TRUE;
3295 
3296  break;
3297  }
3299  case PROPRULE_3_TTEF:
3300  {
3301  int begin;
3302  int end;
3303 
3304  begin = inferInfoGetData1(inferinfo);
3305  end = inferInfoGetData2(inferinfo);
3306  assert(begin < end);
3307 
3308  begin = MAX(begin, hmin);
3309  end = MIN(end, hmax);
3310 
3311  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3312  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3313 
3314  break;
3315  }
3316 
3317  case PROPRULE_0_INVALID:
3318  default:
3319  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3320  SCIPABORT();
3321  return SCIP_INVALIDDATA; /*lint !e527*/
3322  }
3323 
3324  (*result) = SCIP_SUCCESS;
3325 
3326  return SCIP_OKAY;
3327 }
3328 
3329 /**@} */
3330 
3331 
3332 /**@name Enforcement methods
3333  *
3334  * @{
3335  */
3336 
3337 /** apply all fixings which are given by the alternative bounds */
3338 static
3340  SCIP* scip, /**< SCIP data structure */
3341  SCIP_VAR** vars, /**< array of active variables */
3342  int nvars, /**< number of active variables */
3343  int* alternativelbs, /**< alternative lower bounds */
3344  int* alternativeubs, /**< alternative lower bounds */
3345  int* downlocks, /**< number of constraints with down lock participating by the computation */
3346  int* uplocks, /**< number of constraints with up lock participating by the computation */
3347  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3348  )
3349 {
3350  int v;
3351 
3352  for( v = 0; v < nvars; ++v )
3353  {
3354  SCIP_VAR* var;
3355  SCIP_Real objval;
3356 
3357  var = vars[v];
3358  assert(var != NULL);
3359 
3360  objval = SCIPvarGetObj(var);
3361 
3362  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3363  {
3364  int ub;
3365 
3366  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3367 
3368  if( alternativelbs[v] <= ub )
3369  {
3370  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3371  (*branched) = TRUE;
3372 
3373  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3374  SCIPvarGetLbLocal(var), alternativelbs[v]);
3375 
3376  return SCIP_OKAY;
3377  }
3378  }
3379 
3380  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3381  {
3382  int lb;
3383 
3384  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3385 
3386  if( alternativeubs[v] >= lb )
3387  {
3388  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3389  (*branched) = TRUE;
3390 
3391  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3392  alternativeubs[v], SCIPvarGetUbLocal(var));
3393 
3394  return SCIP_OKAY;
3395  }
3396  }
3397  }
3398 
3399  return SCIP_OKAY;
3400 }
3401 
3402 /** remove the capacity requirments for all job which start at the curtime */
3403 static
3405  SCIP_CONSDATA* consdata, /**< constraint data */
3406  int curtime, /**< current point in time */
3407  int* starttimes, /**< array of start times */
3408  int* startindices, /**< permutation with respect to the start times */
3409  int* freecapacity, /**< pointer to store the resulting free capacity */
3410  int* idx, /**< pointer to index in start time array */
3411  int nvars /**< number of vars in array of starttimes and startindices */
3412  )
3413 {
3414 #if defined SCIP_DEBUG && !defined NDEBUG
3415  int oldidx;
3416 
3417  assert(idx != NULL);
3418  oldidx = *idx;
3419 #else
3420  assert(idx != NULL);
3421 #endif
3422 
3423  assert(starttimes != NULL);
3424  assert(starttimes != NULL);
3425  assert(freecapacity != NULL);
3426  assert(starttimes[*idx] == curtime);
3427  assert(consdata->demands != NULL);
3428  assert(freecapacity != idx);
3429 
3430  /* subtract all capacity needed up to this point */
3431  (*freecapacity) -= consdata->demands[startindices[*idx]];
3432 
3433  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3434  {
3435  ++(*idx);
3436  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3437  assert(freecapacity != idx);
3438  }
3439 #ifdef SCIP_DEBUG
3440  assert(oldidx <= *idx);
3441 #endif
3442 }
3443 
3444 /** add the capacity requirments for all job which end at the curtime */
3445 static
3446 void addEndingJobDemands(
3447  SCIP_CONSDATA* consdata, /**< constraint data */
3448  int curtime, /**< current point in time */
3449  int* endtimes, /**< array of end times */
3450  int* endindices, /**< permutation with rspect to the end times */
3451  int* freecapacity, /**< pointer to store the resulting free capacity */
3452  int* idx, /**< pointer to index in end time array */
3453  int nvars /**< number of vars in array of starttimes and startindices */
3454  )
3455 {
3456 #if defined SCIP_DEBUG && !defined NDEBUG
3457  int oldidx;
3458  oldidx = *idx;
3459 #endif
3460 
3461  /* free all capacity usages of jobs the are no longer running */
3462  while( endtimes[*idx] <= curtime && *idx < nvars)
3463  {
3464  (*freecapacity) += consdata->demands[endindices[*idx]];
3465  ++(*idx);
3466  }
3467 
3468 #ifdef SCIP_DEBUG
3469  assert(oldidx <= *idx);
3470 #endif
3471 }
3472 
3473 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3474 static
3476  SCIP* scip, /**< SCIP data structure */
3477  SCIP_CONSDATA* consdata, /**< constraint handler data */
3478  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3479  int* timepoint /**< pointer to store the time point of the peak */
3480  )
3481 {
3482  int* starttimes; /* stores when each job is starting */
3483  int* endtimes; /* stores when each job ends */
3484  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3485  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3486 
3487  int nvars; /* number of activities for this constraint */
3488  int freecapacity; /* remaining capacity */
3489  int curtime; /* point in time which we are just checking */
3490  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3491 
3492  int hmin;
3493  int hmax;
3494 
3495  int j;
3496 
3497  assert(consdata != NULL);
3498 
3499  nvars = consdata->nvars;
3500  assert(nvars > 0);
3501 
3502  *timepoint = consdata->hmax;
3503 
3504  assert(consdata->vars != NULL);
3505 
3506  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3507  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3508  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3509  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3510 
3511  /* create event point arrays */
3512  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3513  starttimes, endtimes, startindices, endindices);
3514 
3515  endindex = 0;
3516  freecapacity = consdata->capacity;
3517  hmin = consdata->hmin;
3518  hmax = consdata->hmax;
3519 
3520  /* check each startpoint of a job whether the capacity is kept or not */
3521  for( j = 0; j < nvars; ++j )
3522  {
3523  curtime = starttimes[j];
3524  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3525 
3526  if( curtime >= hmax )
3527  break;
3528 
3529  /* remove the capacity requirments for all job which start at the curtime */
3530  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3531 
3532  /* add the capacity requirments for all job which end at the curtime */
3533  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3534 
3535  assert(freecapacity <= consdata->capacity);
3536  assert(endindex <= nvars);
3537 
3538  /* endindex - points to the next job which will finish */
3539  /* j - points to the last job that has been released */
3540 
3541  /* if free capacity is smaller than zero, then add branching candidates */
3542  if( freecapacity < 0 && curtime >= hmin )
3543  {
3544  *timepoint = curtime;
3545  break;
3546  }
3547  } /*lint --e{850}*/
3548 
3549  /* free all buffer arrays */
3550  SCIPfreeBufferArray(scip, &endindices);
3551  SCIPfreeBufferArray(scip, &startindices);
3552  SCIPfreeBufferArray(scip, &endtimes);
3553  SCIPfreeBufferArray(scip, &starttimes);
3554 
3555  return SCIP_OKAY;
3556 }
3557 
3558 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3559 static
3561  SCIP* scip, /**< SCIP data structure */
3562  SCIP_CONS** conss, /**< constraints to be processed */
3563  int nconss, /**< number of constraints */
3564  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3565  int* nbranchcands /**< pointer to store the number of branching variables */
3566  )
3567 {
3568  SCIP_HASHTABLE* collectedvars;
3569  int c;
3570 
3571  assert(scip != NULL);
3572  assert(conss != NULL);
3573 
3574  /* create a hash table */
3575  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3576  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3577 
3578  assert(scip != NULL);
3579  assert(conss != NULL);
3580 
3581  for( c = 0; c < nconss; ++c )
3582  {
3583  SCIP_CONS* cons;
3584  SCIP_CONSDATA* consdata;
3585 
3586  int curtime;
3587  int j;
3588 
3589  cons = conss[c];
3590  assert(cons != NULL);
3591 
3592  if( !SCIPconsIsActive(cons) )
3593  continue;
3594 
3595  consdata = SCIPconsGetData(cons);
3596  assert(consdata != NULL);
3597 
3598  /* get point in time when capacity is exceeded */
3599  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3600 
3601  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3602  continue;
3603 
3604  /* report all variables that are running at that point in time */
3605  for( j = 0; j < consdata->nvars; ++j )
3606  {
3607  SCIP_VAR* var;
3608  int lb;
3609  int ub;
3610 
3611  var = consdata->vars[j];
3612  assert(var != NULL);
3613 
3614  /* check if the variable was already added */
3615  if( SCIPhashtableExists(collectedvars, (void*)var) )
3616  continue;
3617 
3618  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3619  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3620 
3621  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3622  {
3623  SCIP_Real solval;
3624  SCIP_Real score;
3625 
3626  solval = SCIPgetSolVal(scip, sol, var);
3627  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3628 
3629  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3630  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3631  (*nbranchcands)++;
3632 
3633  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3634  }
3635  }
3636  }
3637 
3638  SCIPhashtableFree(&collectedvars);
3639 
3640  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3641 
3642  return SCIP_OKAY;
3643 }
3644 
3645 /** enforcement of an LP, pseudo, or relaxation solution */
3646 static
3648  SCIP* scip, /**< SCIP data structure */
3649  SCIP_CONS** conss, /**< constraints to be processed */
3650  int nconss, /**< number of constraints */
3651  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3652  SCIP_Bool branch, /**< should branching candidates be collected */
3653  SCIP_RESULT* result /**< pointer to store the result */
3654  )
3655 {
3656  if( branch )
3657  {
3658  int nbranchcands;
3659 
3660  nbranchcands = 0;
3661  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3662 
3663  if( nbranchcands > 0 )
3664  (*result) = SCIP_INFEASIBLE;
3665  }
3666  else
3667  {
3668  SCIP_Bool violated;
3669  int c;
3670 
3671  violated = FALSE;
3672 
3673  /* first check if a constraints is violated */
3674  for( c = 0; c < nconss && !violated; ++c )
3675  {
3676  SCIP_CONS* cons;
3677 
3678  cons = conss[c];
3679  assert(cons != NULL);
3680 
3681  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3682  }
3683 
3684  if( violated )
3685  (*result) = SCIP_INFEASIBLE;
3686  }
3687 
3688  return SCIP_OKAY;
3689 }
3690 
3691 /**@} */
3692 
3693 /**@name Propagation
3694  *
3695  * @{
3696  */
3697 
3698 /** check if cumulative constraint is independently of all other constraints */
3699 static
3701  SCIP_CONS* cons /**< cumulative constraint */
3702  )
3703 {
3704  SCIP_CONSDATA* consdata;
3705  SCIP_VAR** vars;
3706  SCIP_Bool* downlocks;
3707  SCIP_Bool* uplocks;
3708  int nvars;
3709  int v;
3710 
3711  consdata = SCIPconsGetData(cons);
3712  assert(consdata != NULL);
3713 
3714  nvars = consdata->nvars;
3715  vars = consdata->vars;
3716  downlocks = consdata->downlocks;
3717  uplocks = consdata->uplocks;
3718 
3719  /* check if the cumulative constraint has the only locks on the involved variables */
3720  for( v = 0; v < nvars; ++v )
3721  {
3722  SCIP_VAR* var;
3723 
3724  var = vars[v];
3725  assert(var != NULL);
3726 
3727  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3728  || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3729  return FALSE;
3730  }
3731 
3732  return TRUE;
3733 }
3734 
3735 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3736  * (dual reductions)
3737  */
3738 static
3740  SCIP* scip, /**< SCIP data structure */
3741  SCIP_CONS* cons, /**< cumulative constraint */
3742  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3743  int* nchgbds, /**< pointer to store the number changed variable bounds */
3744  int* nfixedvars, /**< pointer to count number of fixings */
3745  int* ndelconss, /**< pointer to count number of deleted constraints */
3746  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3747  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3748  )
3749 {
3750  SCIP_CONSDATA* consdata;
3751  SCIP_VAR** vars;
3752  SCIP_Real* objvals;
3753  SCIP_Real* lbs;
3754  SCIP_Real* ubs;
3755  SCIP_Real timelimit;
3756  SCIP_Real memorylimit;
3757  SCIP_Bool solved;
3758  SCIP_Bool error;
3759 
3760  int ncheckconss;
3761  int nvars;
3762  int v;
3763 
3764  assert(scip != NULL);
3765  assert(!SCIPconsIsModifiable(cons));
3766  assert(SCIPgetNConss(scip) > 0);
3767 
3768  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3769  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3770  */
3771  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3772  return SCIP_OKAY;
3773 
3774  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3775  * use the locks to decide for a dual reduction using this constraint;
3776  */
3777  if( !SCIPconsIsChecked(cons) )
3778  return SCIP_OKAY;
3779 
3780  ncheckconss = SCIPgetNCheckConss(scip);
3781 
3782  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3783  * presolved problem do nothing execpt to change the parameter settings
3784  */
3785  if( ncheckconss == 1 )
3786  {
3787  /* shrink the minimal maximum value for the conflict length */
3788  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3789 
3790  /* use only first unique implication point */
3791  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3792 
3793  /* do not use reconversion conflicts */
3794  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3795 
3796  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3797  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3798 
3799  /* increase the number of conflicts which induce a restart */
3800  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3801 
3802  /* weight the variable which made into a conflict */
3803  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3804 
3805  /* do not check pseudo solution (for performance reasons) */
3806  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3807 
3808  /* use value based history to detect a reasonable branching point */
3809  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3810 
3811  /* turn of LP relaxation */
3812  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3813 
3814  /* prefer the down branch in case the value based history does not suggest something */
3815  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3816 
3817  /* accept any bound change */
3818  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3819 
3820  /* allow for at most 10 restart, after that the value based history should be reliable */
3821  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3822 
3823  /* set priority for depth first search to highest possible value */
3824  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3825 
3826  return SCIP_OKAY;
3827  }
3828 
3829  consdata = SCIPconsGetData(cons);
3830  assert(consdata != NULL);
3831 
3832  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3833  * fail on the first place
3834  */
3835  if( consdata->triedsolving )
3836  return SCIP_OKAY;
3837 
3838  /* check if constraint is independently */
3839  if( !isConsIndependently(cons) )
3840  return SCIP_OKAY;
3841 
3842  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3843  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3844  */
3845  consdata->triedsolving = TRUE;
3846 
3847  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3848  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3849  SCIPdebugPrintCons(scip, cons, NULL);
3850 
3851  nvars = consdata->nvars;
3852  vars = consdata->vars;
3853 
3854  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3855  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3856  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3857 
3858  for( v = 0; v < nvars; ++v )
3859  {
3860  SCIP_VAR* var;
3861 
3862  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3863  * array
3864  */
3865  var = vars[v];
3866  assert(var != NULL);
3867 
3868  lbs[v] = SCIPvarGetLbLocal(var);
3869  ubs[v] = SCIPvarGetUbLocal(var);
3870 
3871  objvals[v] = SCIPvarGetObj(var);
3872  }
3873 
3874  /* check whether there is enough time and memory left */
3875  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3876  if( !SCIPisInfinity(scip, timelimit) )
3877  timelimit -= SCIPgetSolvingTime(scip);
3878  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3879 
3880  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3881  if( !SCIPisInfinity(scip, memorylimit) )
3882  {
3883  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3884  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3885  }
3886 
3887  /* solve the cumulative condition separately */
3888  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3889  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3890 
3891  if( !(*cutoff) && !(*unbounded) && !error )
3892  {
3893  SCIP_Bool infeasible;
3894  SCIP_Bool tightened;
3895  SCIP_Bool allfixed;
3896 
3897  allfixed = TRUE;
3898 
3899  for( v = 0; v < nvars; ++v )
3900  {
3901  /* check if variable is fixed */
3902  if( lbs[v] + 0.5 > ubs[v] )
3903  {
3904  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3905  assert(!infeasible);
3906 
3907  if( tightened )
3908  {
3909  (*nfixedvars)++;
3910  consdata->triedsolving = FALSE;
3911  }
3912  }
3913  else
3914  {
3915  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3916  assert(!infeasible);
3917 
3918  if( tightened )
3919  {
3920  (*nchgbds)++;
3921  consdata->triedsolving = FALSE;
3922  }
3923 
3924  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3925  assert(!infeasible);
3926 
3927  if( tightened )
3928  {
3929  (*nchgbds)++;
3930  consdata->triedsolving = FALSE;
3931  }
3932 
3933  allfixed = FALSE;
3934  }
3935  }
3936 
3937  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3938  if( allfixed )
3939  {
3940  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3941  (*ndelconss)++;
3942  }
3943  }
3944 
3945  SCIPfreeBufferArray(scip, &objvals);
3946  SCIPfreeBufferArray(scip, &ubs);
3947  SCIPfreeBufferArray(scip, &lbs);
3948 
3949  return SCIP_OKAY;
3950 }
3951 
3952 /** start conflict analysis to analysis the core insertion which is infeasible */
3953 static
3955  SCIP* scip, /**< SCIP data structure */
3956  int nvars, /**< number of start time variables (activities) */
3957  SCIP_VAR** vars, /**< array of start time variables */
3958  int* durations, /**< array of durations */
3959  int* demands, /**< array of demands */
3960  int capacity, /**< cumulative capacity */
3961  int hmin, /**< left bound of time axis to be considered (including hmin) */
3962  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3963  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3964  int inferduration, /**< duration of the start time variable */
3965  int inferdemand, /**< demand of the start time variable */
3966  int inferpeak, /**< profile preak which causes the infeasibilty */
3967  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3968  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3969  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3970  )
3971 {
3972  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3973  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3974  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3975 
3976  /* initialize conflict analysis if conflict analysis is applicable */
3978  {
3980 
3981  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3982  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3983 
3984  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3985 
3986  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3987  if( usebdwidening )
3988  {
3989  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3990  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3991  }
3992  else
3993  {
3994  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3995  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3996  }
3997 
3998  *initialized = TRUE;
3999  }
4000 
4001  return SCIP_OKAY;
4002 }
4003 
4004 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4005  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
4006  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4007  * analysis
4008  */
4009 static
4011  SCIP* scip, /**< SCIP data structure */
4012  int nvars, /**< number of start time variables (activities) */
4013  SCIP_VAR** vars, /**< array of start time variables */
4014  int* durations, /**< array of durations */
4015  int* demands, /**< array of demands */
4016  int capacity, /**< cumulative capacity */
4017  int hmin, /**< left bound of time axis to be considered (including hmin) */
4018  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4019  SCIP_CONS* cons, /**< constraint which is propagated */
4020  SCIP_PROFILE* profile, /**< resource profile */
4021  int idx, /**< position of the variable to propagate */
4022  int* nchgbds, /**< pointer to store the number of bound changes */
4023  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
4024  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4025  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4026  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4027  )
4028 {
4029  SCIP_VAR* var;
4030  int ntimepoints;
4031  int duration;
4032  int demand;
4033  int peak;
4034  int newlb;
4035  int est;
4036  int lst;
4037  int pos;
4038 
4039  var = vars[idx];
4040  assert(var != NULL);
4041 
4042  duration = durations[idx];
4043  assert(duration > 0);
4044 
4045  demand = demands[idx];
4046  assert(demand > 0);
4047 
4048  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4049  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4050  ntimepoints = SCIPprofileGetNTimepoints(profile);
4051 
4052  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4053  * load which we have at the earliest start time (lower bound)
4054  */
4055  (void) SCIPprofileFindLeft(profile, est, &pos);
4056 
4057  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4058 
4059  /* we now trying to move the earliest start time in steps of at most "duration" length */
4060  do
4061  {
4062  INFERINFO inferinfo;
4063  SCIP_Bool tightened;
4064  int ect;
4065 
4066 #ifndef NDEBUG
4067  {
4068  /* in debug mode we check that we adjust the search position correctly */
4069  int tmppos;
4070 
4071  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4072  assert(pos == tmppos);
4073  }
4074 #endif
4075  ect = est + duration;
4076  peak = -1;
4077 
4078  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4079  * want a peak which is closest to the earliest completion time
4080  */
4081  do
4082  {
4083  /* check if the profile load conflicts with the demand of the start time variable */
4084  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4085  peak = pos;
4086 
4087  pos++;
4088  }
4089  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4090 
4091  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4092  * conflicting to the core resource profile
4093  */
4094  /* coverity[check_after_sink] */
4095  if( peak == -1 )
4096  break;
4097 
4098  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4099  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4100  * earliest completion time (the remaining move will done in the next loop)
4101  */
4102  newlb = SCIPprofileGetTime(profile, peak+1);
4103  newlb = MIN(newlb, ect);
4104 
4105  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4106  if( newlb > lst )
4107  {
4108  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4109 
4110  /* use conflict analysis to analysis the core insertion which was infeasible */
4111  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4112  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4113 
4114  if( explanation != NULL )
4115  explanation[idx] = TRUE;
4116 
4117  *infeasible = TRUE;
4118 
4119  break;
4120  }
4121 
4122  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4123  * bound change
4124  */
4125  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4126 
4127  /* perform the bound lower bound change */
4128  if( inferInfoIsValid(inferinfo) )
4129  {
4130  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4131  }
4132  else
4133  {
4134  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4135  }
4136  assert(tightened);
4137  assert(!(*infeasible));
4138 
4139  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4140  (*nchgbds)++;
4141 
4142  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4144 
4145  /* adjust the earliest start time
4146  *
4147  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4148  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4149  * involved.
4150  */
4151  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4152  assert(est >= newlb);
4153 
4154  /* adjust the search position for the resource profile for the next step */
4155  if( est == SCIPprofileGetTime(profile, peak+1) )
4156  pos = peak + 1;
4157  else
4158  pos = peak;
4159  }
4160  while( est < lst );
4161 
4162  return SCIP_OKAY;
4163 }
4164 
4165 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4166  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4167  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4168  * analysis
4169  */
4170 static
4172  SCIP* scip, /**< SCIP data structure */
4173  SCIP_VAR* var, /**< start time variable to propagate */
4174  int duration, /**< duration of the job */
4175  int demand, /**< demand of the job */
4176  int capacity, /**< cumulative capacity */
4177  SCIP_CONS* cons, /**< constraint which is propagated */
4178  SCIP_PROFILE* profile, /**< resource profile */
4179  int idx, /**< position of the variable to propagate */
4180  int* nchgbds /**< pointer to store the number of bound changes */
4181  )
4182 {
4183  int ntimepoints;
4184  int newub;
4185  int peak;
4186  int pos;
4187  int est;
4188  int lst;
4189  int lct;
4190 
4191  assert(var != NULL);
4192  assert(duration > 0);
4193  assert(demand > 0);
4194 
4195  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4196  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4197 
4198  /* in case the start time variable is fixed do nothing */
4199  if( est == lst )
4200  return SCIP_OKAY;
4201 
4202  ntimepoints = SCIPprofileGetNTimepoints(profile);
4203 
4204  lct = lst + duration;
4205 
4206  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4207  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4208  * position gives us the load which we have at the latest completion time minus one
4209  */
4210  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4211 
4212  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4213  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4214 
4215  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4216  return SCIP_OKAY;
4217 
4218  /* we now trying to move the latest start time in steps of at most "duration" length */
4219  do
4220  {
4221  INFERINFO inferinfo;
4222  SCIP_Bool tightened;
4223  SCIP_Bool infeasible;
4224 
4225  peak = -1;
4226 
4227 #ifndef NDEBUG
4228  {
4229  /* in debug mode we check that we adjust the search position correctly */
4230  int tmppos;
4231 
4232  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4233  assert(pos == tmppos);
4234  }
4235 #endif
4236 
4237  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4238  * want a peak which is closest to the latest start time
4239  */
4240  do
4241  {
4242  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4243  peak = pos;
4244 
4245  pos--;
4246  }
4247  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4248 
4249  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4250  * to the core resource profile
4251  */
4252  /* coverity[check_after_sink] */
4253  if( peak == -1 )
4254  break;
4255 
4256  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4257  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4258  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4259  * doing in the next loop)
4260  */
4261  newub = SCIPprofileGetTime(profile, peak);
4262  newub = MAX(newub, lst) - duration;
4263  assert(newub >= est);
4264 
4265  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4266  * bound change
4267  */
4268  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4269 
4270  /* perform the bound upper bound change */
4271  if( inferInfoIsValid(inferinfo) )
4272  {
4273  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4274  }
4275  else
4276  {
4277  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4278  }
4279  assert(tightened);
4280  assert(!infeasible);
4281 
4282  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4283  (*nchgbds)++;
4284 
4285  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4287 
4288  /* adjust the latest start and completion time
4289  *
4290  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4291  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4292  * involved.
4293  */
4294  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4295  assert(lst <= newub);
4296  lct = lst + duration;
4297 
4298  /* adjust the search position for the resource profile for the next step */
4299  if( SCIPprofileGetTime(profile, peak) == lct )
4300  pos = peak - 1;
4301  else
4302  pos = peak;
4303  }
4304  while( est < lst );
4305 
4306  return SCIP_OKAY;
4307 }
4308 
4309 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4310  * points
4311  */
4312 static
4314  SCIP_PROFILE* profile, /**< core profile */
4315  int nvars, /**< number of start time variables (activities) */
4316  int* ests, /**< array of sorted earliest start times */
4317  int* lcts, /**< array of sorted latest completion times */
4318  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4319  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4320  )
4321 {
4322  int ntimepoints;
4323  int energy;
4324  int t;
4325  int v;
4326 
4327  ntimepoints = SCIPprofileGetNTimepoints(profile);
4328  t = ntimepoints - 1;
4329  energy = 0;
4330 
4331  /* compute core energy after the earliest start time of each job */
4332  for( v = nvars-1; v >= 0; --v )
4333  {
4334  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4335  {
4336  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4337  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4338  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4339  t--;
4340  }
4341  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4342 
4343  /* maybe ests[j] is in-between two timepoints */
4344  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4345  {
4346  assert(t > 0);
4347  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4348  }
4349  else
4350  coreEnergyAfterEst[v] = energy;
4351  }
4352 
4353  t = ntimepoints - 1;
4354  energy = 0;
4355 
4356  /* compute core energy after the latest completion time of each job */
4357  for( v = nvars-1; v >= 0; --v )
4358  {
4359  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4360  {
4361  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4362  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4363  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4364  t--;
4365  }
4366  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4367 
4368  /* maybe lcts[j] is in-between two timepoints */
4369  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4370  {
4371  assert(t > 0);
4372  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4373  }
4374  else
4375  coreEnergyAfterLct[v] = energy;
4376  }
4377 }
4378 
4379 /** collect earliest start times, latest completion time, and free energy contributions */
4380 static
4381 void collectDataTTEF(
4382  SCIP* scip, /**< SCIP data structure */
4383  int nvars, /**< number of start time variables (activities) */
4384  SCIP_VAR** vars, /**< array of start time variables */
4385  int* durations, /**< array of durations */
4386  int* demands, /**< array of demands */
4387  int hmin, /**< left bound of time axis to be considered (including hmin) */
4388  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4389  int* permests, /**< array to store the variable positions */
4390  int* ests, /**< array to store earliest start times */
4391  int* permlcts, /**< array to store the variable positions */
4392  int* lcts, /**< array to store latest completion times */
4393  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4394  int* lsts, /**< array to store latest start times of the flexible part of the job */
4395  int* flexenergies /**< array to store the flexible energies of each job */
4396  )
4397 {
4398  int v;
4399 
4400  for( v = 0; v < nvars; ++ v)
4401  {
4402  int duration;
4403  int leftadjust;
4404  int rightadjust;
4405  int core;
4406  int est;
4407  int lct;
4408  int ect;
4409  int lst;
4410 
4411  duration = durations[v];
4412  assert(duration > 0);
4413 
4414  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4415  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4416  ect = est + duration;
4417  lct = lst + duration;
4418 
4419  ests[v] = est;
4420  lcts[v] = lct;
4421  permests[v] = v;
4422  permlcts[v] = v;
4423 
4424  /* compute core time window which lies within the effective horizon */
4425  core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4426 
4427  /* compute the number of time steps the job could run before the effective horizon */
4428  leftadjust = MAX(0, hmin - est);
4429 
4430  /* compute the number of time steps the job could run after the effective horizon */
4431  rightadjust = MAX(0, lct - hmax);
4432 
4433  /* compute for each job the energy which is flexible; meaning not part of the core */
4434  flexenergies[v] = duration - leftadjust - rightadjust - core;
4435  flexenergies[v] = MAX(0, flexenergies[v]);
4436  flexenergies[v] *= demands[v];
4437  assert(flexenergies[v] >= 0);
4438 
4439  /* the earliest completion time of the flexible energy */
4440  ects[v] = MIN(ect, lst);
4441 
4442  /* the latest start time of the flexible energy */
4443  lsts[v] = MAX(ect, lst);
4444  }
4445 }
4446 
4447 /** try to tighten the lower bound of the given variable */
4448 static
4450  SCIP* scip, /**< SCIP data structure */
4451  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4452  int nvars, /**< number of start time variables (activities) */
4453  SCIP_VAR** vars, /**< array of start time variables */
4454  int* durations, /**< array of durations */
4455  int* demands, /**< array of demands */
4456  int capacity, /**< cumulative capacity */
4457  int hmin, /**< left bound of time axis to be considered (including hmin) */
4458  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4459  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4460  int duration, /**< duration of the job */
4461  int demand, /**< demand of the job */
4462  int est, /**< earliest start time of the job */
4463  int ect, /**< earliest completion time of the flexible part of the job */
4464  int lct, /**< latest completion time of the job */
4465  int begin, /**< begin of the time window under investigation */
4466  int end, /**< end of the time window under investigation */
4467  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4468  int* bestlb, /**< pointer to strope the best lower bound change */
4469  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4470  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4471  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4472  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4473  )
4474 {
4475  int newlb;
4476 
4477  assert(begin >= hmin);
4478  assert(end <= hmax);
4479 
4480  /* check if the time-table edge-finding should infer bounds */
4481  if( !conshdlrdata->ttefinfer )
4482  return SCIP_OKAY;
4483 
4484  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4485  if( est >= end || ect <= begin )
4486  return SCIP_OKAY;
4487 
4488  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4489  * skip since the overload check will do the job
4490  */
4491  if( est >= begin && ect <= end )
4492  return SCIP_OKAY;
4493 
4494  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4495  * earliest start time
4496  */
4497  if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4498  return SCIP_OKAY;
4499 
4500  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4501  * present; therefore, we need to add the core;
4502  *
4503  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4504  * compute the earliest completion time of the (whole) job
4505  */
4506  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4507 
4508  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4509  *
4510  * @note we can round down the compute duration w.r.t. the available energy
4511  */
4512  newlb = end - (int) (energy / demand);
4513 
4514  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4515  * bound (latest start time); meaning it is not possible to schedule the job
4516  */
4517  if( newlb > lct - duration )
4518  {
4519  /* initialize conflict analysis if conflict analysis is applicable */
4521  {
4522  SCIP_Real relaxedbd;
4523 
4524  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4525 
4526  /* it is enough to overshoot the upper bound of the variable by one */
4527  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4528 
4529  /* initialize conflict analysis */
4531 
4532  /* added to upper bound (which was overcut be new lower bound) of the variable */
4533  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4534 
4535  /* analyze the infeasible */
4536  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4537  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4538 
4539  (*initialized) = TRUE;
4540  }
4541 
4542  (*cutoff) = TRUE;
4543  }
4544  else if( newlb > (*bestlb) )
4545  {
4546  INFERINFO inferinfo;
4547 
4548  assert(newlb > begin);
4549 
4550  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4551 
4552  /* construct inference information */
4553  (*inferinfos) = inferInfoToInt(inferinfo);
4554  (*bestlb) = newlb;
4555  }
4556 
4557  return SCIP_OKAY;
4558 }
4559 
4560 /** try to tighten the upper bound of the given variable */
4561 static
4563  SCIP* scip, /**< SCIP data structure */
4564  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4565  int nvars, /**< number of start time variables (activities) */
4566  SCIP_VAR** vars, /**< array of start time variables */
4567  int* durations, /**< array of durations */
4568  int* demands, /**< array of demands */
4569  int capacity, /**< cumulative capacity */
4570  int hmin, /**< left bound of time axis to be considered (including hmin) */
4571  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4572  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4573  int duration, /**< duration of the job */
4574  int demand, /**< demand of the job */
4575  int est, /**< earliest start time of the job */
4576  int lst, /**< latest start time of the flexible part of the job */
4577  int lct, /**< latest completion time of the job */
4578  int begin, /**< begin of the time window under investigation */
4579  int end, /**< end of the time window under investigation */
4580  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4581  int* bestub, /**< pointer to strope the best upper bound change */
4582  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4583  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4584  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4585  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4586  )
4587 {
4588  int newub;
4589 
4590  assert(begin >= hmin);
4591  assert(end <= hmax);
4592  assert(est < begin);
4593 
4594  /* check if the time-table edge-finding should infer bounds */
4595  if( !conshdlrdata->ttefinfer )
4596  return SCIP_OKAY;
4597 
4598  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4599  if( lst >= end || lct <= begin )
4600  return SCIP_OKAY;
4601 
4602  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4603  * skip since the overload check will do the job
4604  */
4605  if( lst >= begin && lct <= end )
4606  return SCIP_OKAY;
4607 
4608  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4609  if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4610  return SCIP_OKAY;
4611 
4612  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4613  * present; therefore, we need to add the core;
4614  *
4615  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4616  * latest start of the (whole) job
4617  */
4618  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4619  assert(energy >= 0);
4620 
4621  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4622  *
4623  * @note we can round down the compute duration w.r.t. the available energy
4624  */
4625  assert(demand > 0);
4626  newub = begin - duration + (int) (energy / demand);
4627 
4628  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4629  * bound (earliest start time); meaning it is not possible to schedule the job
4630  */
4631  if( newub < est )
4632  {
4633  /* initialize conflict analysis if conflict analysis is applicable */
4635  {
4636  SCIP_Real relaxedbd;
4637 
4638  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4639 
4640  /* it is enough to undershoot the lower bound of the variable by one */
4641  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4642 
4643  /* initialize conflict analysis */
4645 
4646  /* added to lower bound (which was undercut be new upper bound) of the variable */
4647  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4648 
4649  /* analyze the infeasible */
4650  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4651  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4652 
4653  (*initialized) = TRUE;
4654  }
4655 
4656  (*cutoff) = TRUE;
4657  }
4658  else if( newub < (*bestub) )
4659  {
4660  INFERINFO inferinfo;
4661 
4662  assert(newub < begin);
4663 
4664  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4665 
4666  /* construct inference information */
4667  (*inferinfos) = inferInfoToInt(inferinfo);
4668  (*bestub) = newub;
4669  }
4670 
4671  return SCIP_OKAY;
4672 }
4673 
4674 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4675 static
4677  SCIP* scip, /**< SCIP data structure */
4678  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4679  int nvars, /**< number of start time variables (activities) */
4680  SCIP_VAR** vars, /**< array of start time variables */
4681  int* durations, /**< array of durations */
4682  int* demands, /**< array of demands */
4683  int capacity, /**< cumulative capacity */
4684  int hmin, /**< left bound of time axis to be considered (including hmin) */
4685  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4686  int* newlbs, /**< array to buffer new lower bounds */
4687  int* newubs, /**< array to buffer new upper bounds */
4688  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4689  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4690  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4691  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4692  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4693  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4694  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4695  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4696  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4697  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4698  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4699  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4700  )
4701 {
4702  int coreEnergyAfterEnd;
4703  SCIP_Longint maxavailable;
4704  SCIP_Longint minavailable;
4705  SCIP_Longint totalenergy;
4706  int nests;
4707  int est;
4708  int lct;
4709  int start;
4710  int end;
4711  int v;
4712 
4713  est = INT_MAX;
4714  lct = INT_MIN;
4715 
4716  /* compute earliest start and latest completion time of all jobs */
4717  for( v = 0; v < nvars; ++v )
4718  {
4719  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4720  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4721 
4722  est = MIN(est, start);
4723  lct = MAX(lct, end);
4724  }
4725 
4726  /* adjust the effective time horizon */
4727  hmin = MAX(hmin, est);
4728  hmax = MIN(hmax, lct);
4729 
4730  end = hmax + 1;
4731  coreEnergyAfterEnd = -1;
4732 
4733  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4734  minavailable = maxavailable;
4735  totalenergy = computeTotalEnergy(durations, demands, nvars);
4736 
4737  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4738  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4739  return SCIP_OKAY;
4740 
4741  nests = nvars;
4742 
4743  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4744  * times define the end of the time interval under investigation
4745  */
4746  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4747  {
4748  int flexenergy;
4749  int minbegin;
4750  int lbenergy;
4751  int lbcand;
4752  int i;
4753 
4754  lct = lcts[v];
4755 
4756  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4757  * infinity capacity is available; hence we skip that
4758  */
4759  if( lct > hmax )
4760  continue;
4761 
4762  /* if the latest completion time is smaller then hmin we have to stop */
4763  if( lct <= hmin )
4764  {
4765  assert(v == 0 || lcts[v-1] <= lcts[v]);
4766  break;
4767  }
4768 
4769  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4770  * induced by end was just analyzed
4771  */
4772  if( lct == end )
4773  continue;
4774 
4775  assert(lct < end);
4776 
4777  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4778  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4779  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4780  */
4781  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4782  {
4783  SCIP_Longint freeenergy;
4784 
4785  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4786  assert(coreEnergyAfterEnd >= 0);
4787 
4788  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4789  freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4790 
4791  if( freeenergy <= minavailable )
4792  {
4793  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4794  continue;
4795  }
4796  }
4797 
4798  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4799 
4800  end = lct;
4801  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4802 
4803  flexenergy = 0;
4804  minavailable = maxavailable;
4805  minbegin = hmax;
4806  lbcand = -1;
4807  lbenergy = 0;
4808 
4809  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4810  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4811  * wider
4812  */
4813  for( i = nests-1; i >= 0; --i )
4814  {
4815  SCIP_VAR* var;
4816  SCIP_Longint freeenergy;
4817  int duration;
4818  int demand;
4819  int begin;
4820  int idx;
4821  int lst;
4822 
4823  idx = perm[i];
4824  assert(idx >= 0);
4825  assert(idx < nvars);
4826  assert(!(*cutoff));
4827 
4828  /* the earliest start time of the job */
4829  est = ests[i];
4830 
4831  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4832  * latest completion times (which define end) are scant in non-increasing order
4833  */
4834  if( end <= est )
4835  {
4836  nests--;
4837  continue;
4838  }
4839 
4840  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4841  * current ending time
4842  */
4843  if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4844  break;
4845 
4846  var = vars[idx];
4847  assert(var != NULL);
4848 
4849  duration = durations[idx];
4850  assert(duration > 0);
4851 
4852  demand = demands[idx];
4853  assert(demand > 0);
4854 
4855  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4856 
4857  /* the latest start time of the free part of the job */
4858  lst = lsts[idx];
4859 
4860  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4861  * investigation; hence the overload check will do the the job
4862  */
4863  assert(est <= minbegin);
4864  if( minavailable < maxavailable && est < minbegin )
4865  {
4866  assert(!(*cutoff));
4867 
4868  /* try to tighten the upper bound */
4869  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4870  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4871  initialized, explanation, cutoff) );
4872 
4873  if( *cutoff )
4874  break;
4875  }
4876 
4877  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4878  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4879 
4880  begin = est;
4881  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4882 
4883  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4884  * free energy
4885  */
4886  if( begin < hmin )
4887  break;
4888 
4889  /* compute the contribution to the flexible energy */
4890  if( lct <= end )
4891  {
4892  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4893  assert(lst >= begin);
4894  assert(flexenergies[idx] >= 0);
4895  flexenergy += flexenergies[idx];
4896  }
4897  else
4898  {
4899  /* the job partly overlaps with the end */
4900  int candenergy;
4901  int energy;
4902 
4903  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4904  * w.r.t. latest start time
4905  *
4906  * @note we need to be aware of the effective horizon
4907  */
4908  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4909  assert(end - lst < duration);
4910  assert(energy >= 0);
4911 
4912  /* adjust the flexible energy of the time interval */
4913  flexenergy += energy;
4914 
4915  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4916  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4917  assert(candenergy >= 0);
4918 
4919  /* check if we found a better candidate */
4920  if( candenergy > lbenergy )
4921  {
4922  lbenergy = candenergy;
4923  lbcand = idx;
4924  }
4925  }
4926 
4927  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4928  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4929 
4930  /* compute the energy which is not used yet */
4931  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4932 
4933  /* check overload */
4934  if( freeenergy < 0 )
4935  {
4936  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4937 
4938  /* initialize conflict analysis if conflict analysis is applicable */
4940  {
4941  /* analyze infeasibilty */
4943 
4944  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4945  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4946  conshdlrdata->usebdwidening, explanation) );
4947 
4948  (*initialized) = TRUE;
4949  }
4950 
4951  (*cutoff) = TRUE;
4952 
4953  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4954  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4955 
4956  break;
4957  }
4958 
4959  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4960  if( lbenergy > 0 && freeenergy < lbenergy )
4961  {
4962  SCIP_Longint energy;
4963  int newlb;
4964  int ect;
4965 
4966  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4967  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4968 
4969  /* remove the energy of our job from the ... */
4970  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4971 
4972  newlb = end - (int)(energy / demands[lbcand]);
4973 
4974  if( newlb > lst )
4975  {
4976  /* initialize conflict analysis if conflict analysis is applicable */
4978  {
4979  SCIP_Real relaxedbd;
4980 
4981  /* analyze infeasibilty */
4983 
4984  relaxedbd = lst + 1.0;
4985 
4986  /* added to upper bound (which was overcut be new lower bound) of the variable */
4987  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4988 
4989  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4990  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4991  conshdlrdata->usebdwidening, explanation) );
4992 
4993  (*initialized) = TRUE;
4994  }
4995 
4996  (*cutoff) = TRUE;
4997  break;
4998  }
4999  else if( newlb > newlbs[lbcand] )
5000  {
5001  INFERINFO inferinfo;
5002 
5003  /* construct inference information */
5004  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5005 
5006  /* buffer upper bound change */
5007  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
5008  newlbs[lbcand] = newlb;
5009  }
5010  }
5011 
5012  /* check if the current interval has a smaller free energy */
5013  if( minavailable > freeenergy )
5014  {
5015  minavailable = freeenergy;
5016  minbegin = begin;
5017  }
5018  assert(minavailable >= 0);
5019  }
5020  }
5021 
5022  return SCIP_OKAY;
5023 }
5024 
5025 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
5026 static
5028  SCIP* scip, /**< SCIP data structure */
5029  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5030  int nvars, /**< number of start time variables (activities) */
5031  SCIP_VAR** vars, /**< array of start time variables */
5032  int* durations, /**< array of durations */
5033  int* demands, /**< array of demands */
5034  int capacity, /**< cumulative capacity */
5035  int hmin, /**< left bound of time axis to be considered (including hmin) */
5036  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5037  int* newlbs, /**< array to buffer new lower bounds */
5038  int* newubs, /**< array to buffer new upper bounds */
5039  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5040  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5041  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5042  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5043  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5044  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5045  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5046  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5047  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5048  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5049  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5050  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5051  )
5052 {
5053  int coreEnergyAfterStart;
5054  SCIP_Longint maxavailable;
5055  SCIP_Longint minavailable;
5056  SCIP_Longint totalenergy;
5057  int nlcts;
5058  int begin;
5059  int minest;
5060  int maxlct;
5061  int start;
5062  int end;
5063  int v;
5064 
5065  if( *cutoff )
5066  return SCIP_OKAY;
5067 
5068  begin = hmin - 1;
5069 
5070  minest = INT_MAX;
5071  maxlct = INT_MIN;
5072 
5073  /* compute earliest start and latest completion time of all jobs */
5074  for( v = 0; v < nvars; ++v )
5075  {
5076  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5077  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5078 
5079  minest = MIN(minest, start);
5080  maxlct = MAX(maxlct, end);
5081  }
5082 
5083  /* adjust the effective time horizon */
5084  hmin = MAX(hmin, minest);
5085  hmax = MIN(hmax, maxlct);
5086 
5087  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5088  totalenergy = computeTotalEnergy(durations, demands, nvars);
5089 
5090  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5091  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5092  return SCIP_OKAY;
5093 
5094  nlcts = 0;
5095 
5096  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5097  * define the start of the time interval under investigation
5098  */
5099  for( v = 0; v < nvars; ++v )
5100  {
5101  int flexenergy;
5102  int minend;
5103  int ubenergy;
5104  int ubcand;
5105  int est;
5106  int i;
5107 
5108  est = ests[v];
5109 
5110  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5111  * infinity capacity is available; hence we skip that
5112  */
5113  if( est < hmin )
5114  continue;
5115 
5116  /* if the earliest start time is larger or equal then hmax we have to stop */
5117  if( est >= hmax )
5118  break;
5119 
5120  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5121  * induced by start was just analyzed
5122  */
5123  if( est == begin )
5124  continue;
5125 
5126  assert(est > begin);
5127 
5128  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5129 
5130  begin = est;
5131  coreEnergyAfterStart = coreEnergyAfterEst[v];
5132 
5133  flexenergy = 0;
5134  minavailable = maxavailable;
5135  minend = hmin;
5136  ubcand = -1;
5137  ubenergy = 0;
5138 
5139  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5140  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5141  */
5142  for( i = nlcts; i < nvars; ++i )
5143  {
5144  SCIP_VAR* var;
5145  SCIP_Longint freeenergy;
5146  int duration;
5147  int demand;
5148  int idx;
5149  int lct;
5150  int ect;
5151 
5152  idx = perm[i];
5153  assert(idx >= 0);
5154  assert(idx < nvars);
5155  assert(!(*cutoff));
5156 
5157  /* the earliest start time of the job */
5158  lct = lcts[i];
5159 
5160  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5161  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5162  */
5163  if( lct <= begin )
5164  {
5165  nlcts++;
5166  continue;
5167  }
5168 
5169  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5170  * start with current beginning time
5171  */
5172  if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5173  break;
5174 
5175  var = vars[idx];
5176  assert(var != NULL);
5177 
5178  duration = durations[idx];
5179  assert(duration > 0);
5180 
5181  demand = demands[idx];
5182  assert(demand > 0);
5183 
5184  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5185 
5186  /* the earliest completion time of the flexible part of the job */
5187  ect = ects[idx];
5188 
5189  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5190  * investigation; hence the overload check will do the the job
5191  */
5192  assert(lct >= minend);
5193  if( minavailable < maxavailable && lct > minend )
5194  {
5195  assert(!(*cutoff));
5196 
5197  /* try to tighten the upper bound */
5198  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5199  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5200  initialized, explanation, cutoff) );
5201 
5202  if( *cutoff )
5203  return SCIP_OKAY;
5204  }
5205 
5206  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5207  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5208 
5209  end = lct;
5210  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5211 
5212  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5213  * free energy
5214  */
5215  if( end > hmax )
5216  break;
5217 
5218  /* compute the contribution to the flexible energy */
5219  if( est >= begin )
5220  {
5221  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5222  assert(ect <= end);
5223  assert(flexenergies[idx] >= 0);
5224  flexenergy += flexenergies[idx];
5225  }
5226  else
5227  {
5228  /* the job partly overlaps with the end */
5229  int candenergy;
5230  int energy;
5231 
5232  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5233  * w.r.t. latest start time
5234  *
5235  * @note we need to be aware of the effective horizon
5236  */
5237  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5238  assert(ect - begin < duration);
5239  assert(energy >= 0);
5240 
5241  /* adjust the flexible energy of the time interval */
5242  flexenergy += energy;
5243 
5244  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5245  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5246  assert(candenergy >= 0);
5247 
5248  /* check if we found a better candidate */
5249  if( candenergy > ubenergy )
5250  {
5251  ubenergy = candenergy;
5252  ubcand = idx;
5253  }
5254  }
5255 
5256  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5257  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5258 
5259  /* compute the energy which is not used yet */
5260  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5261 
5262  /* check overload */
5263  if( freeenergy < 0 )
5264  {
5265  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5266 
5267  /* initialize conflict analysis if conflict analysis is applicable */
5269  {
5270  /* analyze infeasibilty */
5272 
5273  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5274  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5275  conshdlrdata->usebdwidening, explanation) );
5276 
5277  (*initialized) = TRUE;
5278  }
5279 
5280  (*cutoff) = TRUE;
5281 
5282  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5283  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5284 
5285  return SCIP_OKAY;
5286  }
5287 
5288  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5289  if( ubenergy > 0 && freeenergy < ubenergy )
5290  {
5291  SCIP_Longint energy;
5292  int newub;
5293  int lst;
5294 
5295  duration = durations[ubcand];
5296  assert(duration > 0);
5297 
5298  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5299  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5300 
5301  /* remove the energy of our job from the ... */
5302  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5303 
5304  newub = begin - duration + (int)(energy / demands[ubcand]);
5305 
5306  if( newub < ect - duration )
5307  {
5308  /* initialize conflict analysis if conflict analysis is applicable */
5310  {
5311  SCIP_Real relaxedbd;
5312  /* analyze infeasibilty */
5314 
5315  relaxedbd = ect - duration - 1.0;
5316 
5317  /* added to lower bound (which was undercut be new upper bound) of the variable */
5318  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5319 
5320  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5321  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5322  conshdlrdata->usebdwidening, explanation) );
5323 
5324  (*initialized) = TRUE;
5325  }
5326 
5327  (*cutoff) = TRUE;
5328  return SCIP_OKAY;
5329  }
5330  else if( newub < newubs[ubcand] )
5331  {
5332  INFERINFO inferinfo;
5333 
5334  /* construct inference information */
5335  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5336 
5337  /* buffer upper bound change */
5338  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5339  newubs[ubcand] = newub;
5340  }
5341  }
5342 
5343  /* check if the current interval has a smaller free energy */
5344  if( minavailable > freeenergy )
5345  {
5346  minavailable = freeenergy;
5347  minend = end;
5348  }
5349  assert(minavailable >= 0);
5350  }
5351  }
5352 
5353  return SCIP_OKAY;
5354 }
5355 
5356 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5357  * edge-finding
5358  *
5359  * @note The algorithm is based on the following two papers:
5360  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5361  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5362  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5363  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5364  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5365  */
5366 static
5368  SCIP* scip, /**< SCIP data structure */
5369  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5370  SCIP_PROFILE* profile, /**< current core profile */
5371  int nvars, /**< number of start time variables (activities) */
5372  SCIP_VAR** vars, /**< array of start time variables */
5373  int* durations, /**< array of durations */
5374  int* demands, /**< array of demands */
5375  int capacity, /**< cumulative capacity */
5376  int hmin, /**< left bound of time axis to be considered (including hmin) */
5377  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5378  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5379  int* nchgbds, /**< pointer to store the number of bound changes */
5380  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5381  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5382  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5383  )
5384 {
5385  int* coreEnergyAfterEst;
5386  int* coreEnergyAfterLct;
5387  int* flexenergies;
5388  int* permests;
5389  int* permlcts;
5390  int* lcts;
5391  int* ests;
5392  int* ects;
5393  int* lsts;
5394 
5395  int* newlbs;
5396  int* newubs;
5397  int* lbinferinfos;
5398  int* ubinferinfos;
5399 
5400  int v;
5401 
5402  /* check if a cutoff was already detected */
5403  if( (*cutoff) )
5404  return SCIP_OKAY;
5405 
5406  /* check if at least the basic overload checking should be perfomed */
5407  if( !conshdlrdata->ttefcheck )
5408  return SCIP_OKAY;
5409 
5410  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5411 
5412  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5413  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5414  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5415  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5416  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5417  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5418  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5419  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5420  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5421 
5422  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5423  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5424  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5425  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5426 
5427  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5428  for( v = 0; v < nvars; ++v )
5429  {
5430  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5431  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5432  lbinferinfos[v] = 0;
5433  ubinferinfos[v] = 0;
5434  }
5435 
5436  /* collect earliest start times, latest completion time, and free energy contributions */
5437  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5438 
5439  /* sort the earliest start times and latest completion in non-decreasing order */
5440  SCIPsortIntInt(ests, permests, nvars);
5441  SCIPsortIntInt(lcts, permlcts, nvars);
5442 
5443  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5444  * points
5445  */
5446  computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5447 
5448  /* propagate the upper bounds and "opportunistically" the lower bounds */
5449  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5450  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5451  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5452 
5453  /* propagate the lower bounds and "opportunistically" the upper bounds */
5454  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5455  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5456  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5457 
5458  /* apply the buffer bound changes */
5459  for( v = 0; v < nvars && !(*cutoff); ++v )
5460  {
5461  SCIP_Bool infeasible;
5462  SCIP_Bool tightened;
5463 
5464  if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5465  {
5466  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5467  TRUE, &infeasible, &tightened) );
5468  }
5469  else
5470  {
5471  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5472  }
5473 
5474  /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5475  assert(!infeasible);
5476 
5477  if( tightened )
5478  {
5479  (*nchgbds)++;
5480 
5481  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5483  }
5484 
5485  if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5486  {
5487  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5488  TRUE, &infeasible, &tightened) );
5489  }
5490  else
5491  {
5492  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5493  }
5494 
5495  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5496  * bound update can be infeasible
5497  */
5498  if( infeasible )
5499  {
5500  /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5501  * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5502  * be analyzed in the case when begin and end exceed the 15 bit limit
5503  */
5504  if( SCIPisConflictAnalysisApplicable(scip) && inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5505  {
5506  INFERINFO inferinfo;
5507  SCIP_VAR* var;
5508  int begin;
5509  int end;
5510 
5511  var = vars[v];
5512  assert(var != NULL);
5513 
5514  /* initialize conflict analysis */
5516 
5517  /* convert int to inference information */
5518  inferinfo = intToInferInfo(ubinferinfos[v]);
5519 
5520  /* collect time window from inference information */
5521  begin = inferInfoGetData1(inferinfo);
5522  end = inferInfoGetData2(inferinfo);
5523  assert(begin < end);
5524 
5525  /* added to lower bound (which was undercut be new upper bound) of the variable */
5526  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5527 
5528  /* analysis the upper bound change */
5529  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5530  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5531  conshdlrdata->usebdwidening, explanation) );
5532 
5533  (*initialized) = TRUE;
5534  }
5535 
5536  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5537  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5538 
5539  (*cutoff) = TRUE;
5540  break;
5541  }
5542 
5543  if( tightened )
5544  {
5545  (*nchgbds)++;
5546 
5547  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5549  }
5550  }
5551 
5552  SCIPfreeBufferArray(scip, &ubinferinfos);
5553  SCIPfreeBufferArray(scip, &lbinferinfos);
5554  SCIPfreeBufferArray(scip, &newubs);
5555  SCIPfreeBufferArray(scip, &newlbs);
5556 
5557  /* free buffer arrays */
5558  SCIPfreeBufferArray(scip, &lsts);
5559  SCIPfreeBufferArray(scip, &ects);
5560  SCIPfreeBufferArray(scip, &ests);
5561  SCIPfreeBufferArray(scip, &lcts);
5562  SCIPfreeBufferArray(scip, &permests);
5563  SCIPfreeBufferArray(scip, &permlcts);
5564  SCIPfreeBufferArray(scip, &flexenergies);
5565  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5566  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5567 
5568  return SCIP_OKAY;
5569 }
5570 
5571 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5572  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5573  * time table propagator
5574  */
5575 static
5577  SCIP* scip, /**< SCIP data structure */
5578  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5579  SCIP_PROFILE* profile, /**< core profile */
5580  int nvars, /**< number of start time variables (activities) */
5581  SCIP_VAR** vars, /**< array of start time variables */
5582  int* durations, /**< array of durations */
5583  int* demands, /**< array of demands */
5584  int capacity, /**< cumulative capacity */
5585  int hmin, /**< left bound of time axis to be considered (including hmin) */
5586  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5587  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5588  int* nchgbds, /**< pointer to store the number of bound changes */
5589  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5590  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5591  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5592  )
5593 {
5594  SCIP_Bool infeasible;
5595  int v;
5596 
5597  assert(scip != NULL);
5598  assert(nvars > 0);
5599  assert(cons != NULL);
5600  assert(cutoff != NULL);
5601 
5602  /* check if already a cutoff was detected */
5603  if( (*cutoff) )
5604  return SCIP_OKAY;
5605 
5606  /* check if the time tabling should infer bounds */
5607  if( !conshdlrdata->ttinfer )
5608  return SCIP_OKAY;
5609 
5610  assert(*initialized == FALSE);
5611 
5612  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5613  SCIPconsGetName(cons), hmin, hmax, capacity);
5614 
5615  infeasible = FALSE;
5616 
5617  /* if core profile is empty; nothing to do */
5618  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5619  return SCIP_OKAY;
5620 
5621  /* start checking each job whether the bounds can be improved */
5622  for( v = 0; v < nvars; ++v )
5623  {
5624  SCIP_VAR* var;
5625  int demand;
5626  int duration;
5627  int begin;
5628  int end;
5629  int est;
5630  int lst;
5631 
5632  var = vars[v];
5633  assert(var != NULL);
5634 
5635  duration = durations[v];
5636  assert(duration > 0);
5637 
5638  /* collect earliest and latest start time */
5639  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5640  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5641 
5642  /* check if the start time variables is already fixed; in that case we can ignore the job */
5643  if( est == lst )
5644  continue;
5645 
5646  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5647  if( lst + duration <= hmin || est >= hmax )
5648  continue;
5649 
5650  /* compute core interval w.r.t. effective time horizon */
5651  begin = MAX(hmin, lst);
5652  end = MIN(hmax, est + duration);
5653 
5654  demand = demands[v];
5655  assert(demand > 0);
5656 
5657  /* if the job has a core, remove it first */
5658  if( begin < end )
5659  {
5660  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5661  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5662 
5663  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5664  }
5665 
5666  /* first try to update the earliest start time */
5667  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5668  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5669 
5670  if( *cutoff )
5671  break;
5672 
5673  /* second try to update the latest start time */
5674  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5675  profile, v, nchgbds) );
5676 
5677  if( *cutoff )
5678  break;
5679 
5680  /* collect the potentially updated earliest and latest start time */
5681  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5682  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5683 
5684  /* compute core interval w.r.t. effective time horizon */
5685  begin = MAX(hmin, lst);
5686  end = MIN(hmax, est + duration);
5687 
5688  /* after updating the bound we might have a new core */
5689  if( begin < end )
5690  {
5691  int pos;
5692 
5693  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5694  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5695 
5696  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5697 
5698  if( infeasible )
5699  {
5700  /* use conflict analysis to analysis the core insertion which was infeasible */
5701  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5702  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5703 
5704  if( explanation != NULL )
5705  explanation[v] = TRUE;
5706 
5707  (*cutoff) = TRUE;
5708 
5709  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5710  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5711 
5712  break;
5713  }
5714  }
5715  }
5716 
5717  return SCIP_OKAY;
5718 }
5719 
5720 
5721 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5722 struct SCIP_NodeData
5723 {
5724  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5725  SCIP_Real key; /**< key which is to insert the corresponding search node */
5726  int est; /**< earliest start time if the node data belongs to a leaf */
5727  int lct; /**< latest completion time if the node data belongs to a leaf */
5728  int demand; /**< demand of the job if the node data belongs to a leaf */
5729  int duration; /**< duration of the job if the node data belongs to a leaf */
5730  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5731  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5732  SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5733  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5734  int energylambda;
5735  SCIP_Longint enveloplambda;
5736  int idx; /**< index of the start time variable in the (global) variable array */
5737  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5738 };
5739 typedef struct SCIP_NodeData SCIP_NODEDATA;
5741 
5742 /** update node data structure starting from the given node along the path to the root node */
5743 static
5744 void updateEnvelope(
5745  SCIP* scip, /**< SCIP data structure */
5746  SCIP_BTNODE* node /**< search node which inserted */
5747  )
5748 {
5749  SCIP_BTNODE* left;
5750  SCIP_BTNODE* right;
5751  SCIP_NODEDATA* nodedata;
5752  SCIP_NODEDATA* leftdata;
5753  SCIP_NODEDATA* rightdata;
5754 
5755  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5756 
5757  if( SCIPbtnodeIsLeaf(node) )
5758  node = SCIPbtnodeGetParent(node);
5759 
5760  while( node != NULL )
5761  {
5762  /* get node data */
5763  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5764  assert(nodedata != NULL);
5765 
5766  /* collect node data from left node */
5767  left = SCIPbtnodeGetLeftchild(node);
5768  assert(left != NULL);
5769  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5770  assert(leftdata != NULL);
5771 
5772  /* collect node data from right node */
5773  right = SCIPbtnodeGetRightchild(node);
5774  assert(right != NULL);
5775  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5776  assert(rightdata != NULL);
5777 
5778  /* update envelop and energy */
5779  if( leftdata->enveloptheta >= 0 )
5780  {
5781  assert(rightdata->energytheta != -1);
5782  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5783  }
5784  else
5785  nodedata->enveloptheta = rightdata->enveloptheta;
5786 
5787  assert(leftdata->energytheta != -1);
5788  assert(rightdata->energytheta != -1);
5789  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5790 
5791  if( leftdata->enveloplambda >= 0 )
5792  {
5793  assert(rightdata->energytheta != -1);
5794  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5795  }
5796  else
5797  nodedata->enveloplambda = rightdata->enveloplambda;
5798 
5799  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5800  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5801 
5802  SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5803 
5804  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5805  {
5806  assert(rightdata->energytheta != -1);
5807  assert(leftdata->energytheta != -1);
5808  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5809  }
5810  else if( rightdata->energylambda >= 0 )
5811  {
5812  assert(leftdata->energytheta != -1);
5813  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5814  }
5815  else if( leftdata->energylambda >= 0 )
5816  {
5817  assert(rightdata->energytheta != -1);
5818  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5819  }
5820  else
5821  nodedata->energylambda = -1;
5822 
5823  /* go to parent */
5824  node = SCIPbtnodeGetParent(node);
5825  }
5826 
5827  SCIPdebugMsg(scip, "updating done\n");
5828 }
5829 
5830 /** updates the key of the first parent on the trace which comes from left */
5831 static
5832 void updateKeyOnTrace(
5833  SCIP_BTNODE* node, /**< node to start the trace */
5834  SCIP_Real key /**< update search key */
5835  )
5836 {
5837  assert(node != NULL);
5838 
5839  while( !SCIPbtnodeIsRoot(node) )
5840  {
5841  SCIP_BTNODE* parent;
5842 
5843  parent = SCIPbtnodeGetParent(node);
5844  assert(parent != NULL);
5845 
5846  if( SCIPbtnodeIsLeftchild(node) )
5847  {
5848  SCIP_NODEDATA* nodedata;
5849 
5850  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5851  assert(nodedata != NULL);
5852 
5853  nodedata->key = key;
5854  return;
5855  }
5856 
5857  node = parent;
5858  }
5859 }
5860 
5861 
5862 /** deletes the given node and updates all envelops */
5863 static
5865  SCIP* scip, /**< SCIP data structure */
5866  SCIP_BT* tree, /**< binary tree */
5867  SCIP_BTNODE* node /**< node to be deleted */
5868  )
5869 {
5870  SCIP_BTNODE* parent;
5871  SCIP_BTNODE* grandparent;
5872  SCIP_BTNODE* sibling;
5873 
5874  assert(scip != NULL);
5875  assert(tree != NULL);
5876  assert(node != NULL);
5877 
5878  assert(SCIPbtnodeIsLeaf(node));
5879  assert(!SCIPbtnodeIsRoot(node));
5880 
5881  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5882 
5883  parent = SCIPbtnodeGetParent(node);
5884  assert(parent != NULL);
5885  if( SCIPbtnodeIsLeftchild(node) )
5886  {
5887  sibling = SCIPbtnodeGetRightchild(parent);
5888  SCIPbtnodeSetRightchild(parent, NULL);
5889  }
5890  else
5891  {
5892  sibling = SCIPbtnodeGetLeftchild(parent);
5893  SCIPbtnodeSetLeftchild(parent, NULL);
5894  }
5895  assert(sibling != NULL);
5896 
5897  grandparent = SCIPbtnodeGetParent(parent);
5898 
5899  if( grandparent != NULL )
5900  {
5901  /* reset parent of sibling */
5902  SCIPbtnodeSetParent(sibling, grandparent);
5903 
5904  /* reset child of grandparent to sibling */
5905  if( SCIPbtnodeIsLeftchild(parent) )
5906  {
5907  SCIPbtnodeSetLeftchild(grandparent, sibling);
5908  }
5909  else
5910  {
5911  SCIP_NODEDATA* nodedata;
5912 
5913  assert(SCIPbtnodeIsRightchild(parent));
5914  SCIPbtnodeSetRightchild(grandparent, sibling);
5915 
5916  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5917 
5918  updateKeyOnTrace(grandparent, nodedata->key);
5919  }
5920 
5921  updateEnvelope(scip, grandparent);
5922  }
5923  else
5924  {
5925  SCIPbtnodeSetParent(sibling, NULL);
5926 
5927  SCIPbtSetRoot(tree, sibling);
5928  }
5929 
5930  SCIPbtnodeFree(tree, &parent);
5931 
5932  return SCIP_OKAY;
5933 }
5934 
5935 /** moves a node form the theta set into the lambda set and updates the envelops */
5936 static
5938  SCIP* scip, /**< SCIP data structure */
5939  SCIP_BT* tree, /**< binary tree */
5940  SCIP_BTNODE* node /**< node to move into the lambda set */
5941  )
5942 {
5943  SCIP_NODEDATA* nodedata;
5944 
5945  assert(scip != NULL);
5946  assert(tree != NULL);
5947  assert(node != NULL);
5948 
5949  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5950  assert(nodedata != NULL);
5951  assert(nodedata->intheta);
5952 
5953  /* move the contributions form the theta set into the lambda set */
5954  assert(nodedata->enveloptheta != -1);
5955  assert(nodedata->energytheta != -1);
5956  assert(nodedata->enveloplambda == -1);
5957  assert(nodedata->energylambda == -1);
5958  nodedata->enveloplambda = nodedata->enveloptheta;
5959  nodedata->energylambda = nodedata->energytheta;
5960 
5961  nodedata->enveloptheta = -1;
5962  nodedata->energytheta = 0;
5963  nodedata->intheta = FALSE;
5964 
5965  /* update the energy and envelop values on trace */
5966  updateEnvelope(scip, node);
5967 
5968  return SCIP_OKAY;
5969 }
5970 
5971 /** inserts a node into the theta set and update the envelops */
5972 static
5974  SCIP* scip, /**< SCIP data structure */
5975  SCIP_BT* tree, /**< binary tree */
5976  SCIP_BTNODE* node, /**< node to insert */
5977  SCIP_NODEDATA* nodedatas, /**< array of node data */
5978  int* nodedataidx, /**< array of indices for node data */
5979  int* nnodedatas /**< pointer to number of node data */
5980  )
5981 {
5982  /* if the tree is empty the node will be the root node */
5983  if( SCIPbtIsEmpty(tree) )
5984  {
5985  SCIPbtSetRoot(tree, node);
5986  }
5987  else
5988  {
5989  SCIP_NODEDATA* newnodedata;
5990  SCIP_NODEDATA* leafdata;
5991  SCIP_NODEDATA* nodedata;
5992  SCIP_BTNODE* leaf;
5993  SCIP_BTNODE* newnode;
5994  SCIP_BTNODE* parent;
5995 
5996  leaf = SCIPbtGetRoot(tree);
5997  assert(leaf != NULL);
5998 
5999  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6000  assert(leafdata != NULL);
6001 
6002  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6003  assert(nodedata != NULL);
6004  assert(nodedata->intheta);
6005 
6006  /* find the position to insert the node */
6007  while( !SCIPbtnodeIsLeaf(leaf) )
6008  {
6009  if( nodedata->key < leafdata->key )
6010  leaf = SCIPbtnodeGetLeftchild(leaf);
6011  else
6012  leaf = SCIPbtnodeGetRightchild(leaf);
6013 
6014  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6015  assert(leafdata != NULL);
6016  }
6017 
6018  assert(leaf != NULL);
6019  assert(leaf != node);
6020 
6021  /* store node data to be able to delete them latter */
6022  newnodedata = &nodedatas[*nnodedatas];
6023  nodedataidx[*nnodedatas] = *nnodedatas;
6024  ++(*nnodedatas);
6025 
6026  /* init node data */
6027  newnodedata->var = NULL;
6028  newnodedata->key = SCIP_INVALID;
6029  newnodedata->est = INT_MIN;
6030  newnodedata->lct = INT_MAX;
6031  newnodedata->duration = 0;
6032  newnodedata->demand = 0;
6033  newnodedata->enveloptheta = -1;
6034  newnodedata->energytheta = 0;
6035  newnodedata->enveloplambda = -1;
6036  newnodedata->energylambda = -1;
6037  newnodedata->idx = -1;
6038  newnodedata->intheta = TRUE;
6039 
6040  /* create a new node */
6041  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6042  assert(newnode != NULL);
6043 
6044  parent = SCIPbtnodeGetParent(leaf);
6045 
6046  if( parent != NULL )
6047  {
6048  SCIPbtnodeSetParent(newnode, parent);
6049 
6050  /* check if the node is the left child */
6051  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6052  {
6053  SCIPbtnodeSetLeftchild(parent, newnode);
6054  }
6055  else
6056  {
6057  SCIPbtnodeSetRightchild(parent, newnode);
6058  }
6059  }
6060  else
6061  SCIPbtSetRoot(tree, newnode);
6062 
6063  if( nodedata->key < leafdata->key )
6064  {
6065  /* node is on the left */
6066  SCIPbtnodeSetLeftchild(newnode, node);
6067  SCIPbtnodeSetRightchild(newnode, leaf);
6068  newnodedata->key = nodedata->key;
6069  }
6070  else
6071  {
6072  /* leaf is on the left */
6073  SCIPbtnodeSetLeftchild(newnode, leaf);
6074  SCIPbtnodeSetRightchild(newnode, node);
6075  newnodedata->key = leafdata->key;
6076  }
6077 
6078  SCIPbtnodeSetParent(leaf, newnode);
6079  SCIPbtnodeSetParent(node, newnode);
6080  }
6081 
6082  /* update envelop */
6083  updateEnvelope(scip, node);
6084 
6085  return SCIP_OKAY;
6086 }
6087 
6088 /** returns the leaf responsible for the lambda energy */
6089 static
6091  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6092  )
6093 {
6094  SCIP_BTNODE* left;
6095  SCIP_BTNODE* right;
6096  SCIP_NODEDATA* nodedata;
6097  SCIP_NODEDATA* leftdata;
6098  SCIP_NODEDATA* rightdata;
6099 
6100  assert(node != NULL);
6101 
6102  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6103  assert(nodedata != NULL);
6104 
6105  /* check if the node is the (responsible) leaf */
6106  if( SCIPbtnodeIsLeaf(node) )
6107  {
6108  assert(!nodedata->intheta);
6109  return node;
6110  }
6111 
6112  left = SCIPbtnodeGetLeftchild(node);
6113  assert(left != NULL);
6114 
6115  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6116  assert(leftdata != NULL);
6117 
6118  right = SCIPbtnodeGetRightchild(node);
6119  assert(right != NULL);
6120 
6121  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6122  assert(rightdata != NULL);
6123 
6124  assert(nodedata->energylambda != -1);
6125  assert(rightdata->energytheta != -1);
6126 
6127  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6129 
6130  assert(leftdata->energytheta != -1);
6131  assert(rightdata->energylambda != -1);
6132  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6133 
6135 }
6136 
6137 /** returns the leaf responsible for the lambda envelop */
6138 static
6140  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6141  )
6142 {
6143  SCIP_BTNODE* left;
6144  SCIP_BTNODE* right;
6145  SCIP_NODEDATA* nodedata;
6146  SCIP_NODEDATA* leftdata;
6147  SCIP_NODEDATA* rightdata;
6148 
6149  assert(node != NULL);
6150 
6151  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6152  assert(nodedata != NULL);
6153 
6154  /* check if the node is the (responsible) leaf */
6155  if( SCIPbtnodeIsLeaf(node) )
6156  {
6157  assert(!nodedata->intheta);
6158  return node;
6159  }
6160 
6161  left = SCIPbtnodeGetLeftchild(node);
6162  assert(left != NULL);
6163 
6164  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6165  assert(leftdata != NULL);
6166 
6167  right = SCIPbtnodeGetRightchild(node);
6168  assert(right != NULL);
6169 
6170  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6171  assert(rightdata != NULL);
6172 
6173  assert(nodedata->enveloplambda != -1);
6174  assert(rightdata->energytheta != -1);
6175 
6176  /* check if the left or right child is the one defining the envelop for the lambda set */
6177  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6179  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6180  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6182 
6183  assert(rightdata->enveloplambda != -1);
6184  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6185 
6187 }
6188 
6189 
6190 /** reports all elements from set theta to generate a conflicting set */
6191 static
6192 void collectThetaSubtree(
6193  SCIP_BTNODE* node, /**< node within a theta subtree */
6194  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6195  int* nelements, /**< pointer to store the number of elements in omegaset */
6196  int* est, /**< pointer to store the earliest start time of the omega set */
6197  int* lct, /**< pointer to store the latest start time of the omega set */
6198  int* energy /**< pointer to store the energy of the omega set */
6199  )
6200 {
6201  SCIP_NODEDATA* nodedata;
6202 
6203  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6204  assert(nodedata != NULL);
6205 
6206  if( !SCIPbtnodeIsLeaf(node) )
6207  {
6208  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6209  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6210  }
6211  else if( nodedata->intheta )
6212  {
6213  assert(nodedata->var != NULL);
6214  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6215 
6216  omegaset[*nelements] = node;
6217  (*est) = MIN(*est, nodedata->est);
6218  (*lct) = MAX(*lct, nodedata->lct);
6219  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6220  (*nelements)++;
6221  }
6222 }
6223 
6224 
6225 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6226 static
6227 void traceThetaEnvelop(
6228  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6229  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6230  int* nelements, /**< pointer to store the number of elements in omegaset */
6231  int* est, /**< pointer to store the earliest start time of the omega set */
6232  int* lct, /**< pointer to store the latest start time of the omega set */
6233  int* energy /**< pointer to store the energy of the omega set */
6234  )
6235 {
6236  assert(node != NULL);
6237 
6238  if( SCIPbtnodeIsLeaf(node) )
6239  {
6240  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6241  }
6242  else
6243  {
6244  SCIP_BTNODE* left;
6245  SCIP_BTNODE* right;
6246  SCIP_NODEDATA* nodedata;
6247  SCIP_NODEDATA* leftdata;
6248  SCIP_NODEDATA* rightdata;
6249 
6250  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6251  assert(nodedata != NULL);
6252 
6253  left = SCIPbtnodeGetLeftchild(node);
6254  assert(left != NULL);
6255 
6256  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6257  assert(leftdata != NULL);
6258 
6259  right = SCIPbtnodeGetRightchild(node);
6260  assert(right != NULL);
6261 
6262  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6263  assert(rightdata != NULL);
6264 
6265  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6266  assert(nodedata != NULL);
6267 
6268  assert(nodedata->enveloptheta != -1);
6269  assert(rightdata->energytheta != -1);
6270 
6271  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6272  {
6273  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6274  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6275  }
6276  else
6277  {
6278  assert(rightdata->enveloptheta != -1);
6279  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6280  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6281  }
6282  }
6283 }
6284 
6285 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6286 static
6287 void traceLambdaEnergy(
6288  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6289  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6290  int* nelements, /**< pointer to store the number of elements in omega set */
6291  int* est, /**< pointer to store the earliest start time of the omega set */
6292  int* lct, /**< pointer to store the latest start time of the omega set */
6293  int* energy /**< pointer to store the energy of the omega set */
6294  )
6295 {
6296  SCIP_BTNODE* left;
6297  SCIP_BTNODE* right;
6298  SCIP_NODEDATA* nodedata;
6299  SCIP_NODEDATA* leftdata;
6300  SCIP_NODEDATA* rightdata;
6301 
6302  assert(node != NULL);
6303 
6304  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6305  assert(nodedata != NULL);
6306 
6307  /* check if the node is a leaf */
6308  if( SCIPbtnodeIsLeaf(node) )
6309  return;
6310 
6311  left = SCIPbtnodeGetLeftchild(node);
6312  assert(left != NULL);
6313 
6314  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6315  assert(leftdata != NULL);
6316 
6317  right = SCIPbtnodeGetRightchild(node);
6318  assert(right != NULL);
6319 
6320  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6321  assert(rightdata != NULL);
6322 
6323  assert(nodedata->energylambda != -1);
6324  assert(rightdata->energytheta != -1);
6325 
6326  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6327  {
6328  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6329  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6330  }
6331  else
6332  {
6333  assert(leftdata->energytheta != -1);
6334  assert(rightdata->energylambda != -1);
6335  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6336 
6337  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6338  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6339  }
6340 }
6341 
6342 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6343 static
6344 void traceLambdaEnvelop(
6345  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6346  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6347  int* nelements, /**< pointer to store the number of elements in omega set */
6348  int* est, /**< pointer to store the earliest start time of the omega set */
6349  int* lct, /**< pointer to store the latest start time of the omega set */
6350  int* energy /**< pointer to store the energy of the omega set */
6351  )
6352 {
6353  SCIP_BTNODE* left;
6354  SCIP_BTNODE* right;
6355  SCIP_NODEDATA* nodedata;
6356  SCIP_NODEDATA* leftdata;
6357  SCIP_NODEDATA* rightdata;
6358 
6359  assert(node != NULL);
6360 
6361  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6362  assert(nodedata != NULL);
6363 
6364  /* check if the node is a leaf */
6365  if( SCIPbtnodeIsLeaf(node) )
6366  {
6367  assert(!nodedata->intheta);
6368  return;
6369  }
6370 
6371  left = SCIPbtnodeGetLeftchild(node);
6372  assert(left != NULL);
6373 
6374  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6375  assert(leftdata != NULL);
6376 
6377  right = SCIPbtnodeGetRightchild(node);
6378  assert(right != NULL);
6379 
6380  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6381  assert(rightdata != NULL);
6382 
6383  assert(nodedata->enveloplambda != -1);
6384  assert(rightdata->energytheta != -1);
6385 
6386  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6387  {
6388  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6389  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6390  }
6391  else
6392  {
6393  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6394  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6395  {
6396  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6397  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6398  }
6399  else
6400  {
6401  assert(rightdata->enveloplambda != -1);
6402  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6403  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6404  }
6405  }
6406 }
6407 
6408 /** compute the energy contribution by job which corresponds to the given leaf */
6409 static
6411  SCIP_BTNODE* node /**< leaf */
6412  )
6413 {
6414  SCIP_NODEDATA* nodedata;
6415  int duration;
6416 
6417  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6418  assert(nodedata != NULL);
6419  assert(nodedata->var != NULL);
6420 
6421  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6422  assert(duration > 0);
6423 
6424  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6426  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6427 
6428  /* return energy which is contributed by the start time variable */
6429  return nodedata->demand * duration;
6430 }
6431 
6432 /** comparison method for two node data w.r.t. the earliest start time */
6433 static
6434 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6436  int est1;
6437  int est2;
6438 
6439  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6440  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6441 
6442  return (est1 - est2);
6443 }
6444 
6445 /** comparison method for two node data w.r.t. the latest completion time */
6446 static
6447 SCIP_DECL_SORTINDCOMP(compNodedataLct)
6449  SCIP_NODEDATA* nodedatas;
6450 
6451  nodedatas = (SCIP_NODEDATA*) dataptr;
6452  return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6453 }
6454 
6455 
6456 /** an overload was detected; initialized conflict analysis, add an initial reason
6457  *
6458  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6459  */
6460 static
6462  SCIP* scip, /**< SCIP data structure */
6463  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6464  int capacity, /**< cumulative capacity */
6465  int nleaves, /**< number of responsible leaves */
6466  int est, /**< earliest start time of the ...... */
6467  int lct, /**< latest completly time of the .... */
6468  int reportedenergy, /**< energy which already reported */
6469  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6470  int shift, /**< shift applied to all jobs before adding them to the tree */
6471  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6472  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6473  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6474  )
6475 {
6476  SCIP_Longint energy;
6477  int j;
6478 
6479  /* do nothing if conflict analysis is not applicable */
6481  return SCIP_OKAY;
6482 
6483  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6484 
6485  /* compute energy of initial time window */
6486  energy = ((SCIP_Longint) lct - est) * capacity;
6487 
6488  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6489  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6490 
6491  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6492  * thereby, compute the time window of interest
6493  */
6494  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6495  {
6496  SCIP_NODEDATA* nodedata;
6497 
6498  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6499  assert(nodedata != NULL);
6500 
6501  reportedenergy += computeEnergyContribution(leaves[j]);
6502 
6503  /* adjust energy if the earliest start time decrease */
6504  if( nodedata->est < est )
6505  {
6506  est = nodedata->est;
6507  energy = ((SCIP_Longint) lct - est) * capacity;
6508  }
6509  }
6510  assert(reportedenergy > energy);
6511 
6512  SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6513 
6514  /* initialize conflict analysis */
6516 
6517  /* flip earliest start time and latest completion time */
6518  if( !propest )
6519  {
6520  SCIPswapInts(&est, &lct);
6521 
6522  /* shift earliest start time and latest completion time */
6523  lct = shift - lct;
6524  est = shift - est;
6525  }
6526  else
6527  {
6528  /* shift earliest start time and latest completion time */
6529  lct = lct + shift;
6530  est = est + shift;
6531  }
6532 
6533  nleaves = j;
6534 
6535  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6536  * overloaded
6537  */
6538  for( j = nleaves-1; j >= 0; --j )
6539  {
6540  SCIP_NODEDATA* nodedata;
6541 
6542  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6543  assert(nodedata != NULL);
6544  assert(nodedata->var != NULL);
6545 
6546  /* check if bound widening should be used */
6547  if( usebdwidening )
6548  {
6549  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6550  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6551  }
6552  else
6553  {
6554  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6555  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6556  }
6557 
6558  if( explanation != NULL )
6559  explanation[nodedata->idx] = TRUE;
6560  }
6561 
6562  (*initialized) = TRUE;
6563 
6564  return SCIP_OKAY;
6565 }
6566 
6567 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6568  * responsible interval bounds in *est_omega and *lct_omega
6569  */
6570 static
6571 int computeEstOmegaset(
6572  SCIP* scip, /**< SCIP data structure */
6573  int duration, /**< duration of the job to move */
6574  int demand, /**< demand of the job to move */
6575  int capacity, /**< cumulative capacity */
6576  int est, /**< earliest start time of the omega set */
6577  int lct, /**< latest start time of the omega set */
6578  int energy /**< energy of the omega set */
6579  )
6580 {
6581  int newest;
6582 
6583  newest = 0;
6584 
6585  assert(scip != NULL);
6586 
6587  if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6588  {
6589  if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6590  {
6591  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6592  newest += est;
6593  }
6594  }
6595 
6596  return newest;
6597 }
6598 
6599 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6600  *
6601  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6602  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6603  */
6604 static
6606  SCIP* scip, /**< SCIP data structure */
6607  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6608  SCIP_CONS* cons, /**< constraint which is propagated */
6609  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6610  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6611  int capacity, /**< cumulative capacity */
6612  int ncands, /**< number of candidates */
6613  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6614  int shift, /**< shift applied to all jobs before adding them to the tree */
6615  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6616  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6617  int* nchgbds, /**< pointer to store the number of bound changes */
6618  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6619  )
6620 {
6621  SCIP_NODEDATA* rootdata;
6622  int j;
6623 
6624  assert(!SCIPbtIsEmpty(tree));
6625 
6626  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6627  assert(rootdata != NULL);
6628 
6629  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6630  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6631  {
6632  SCIP_NODEDATA* nodedata;
6633 
6634  if( SCIPbtnodeIsRoot(leaves[j]) )
6635  break;
6636 
6637  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6638  assert(nodedata->est != -1);
6639 
6640  /* check if the root lambda envelop exeeds the available capacity */
6641  while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6642  {
6643  SCIP_BTNODE** omegaset;
6644  SCIP_BTNODE* leaf;
6645  SCIP_NODEDATA* leafdata;
6646  int nelements;
6647  int energy;
6648  int newest;
6649  int est;
6650  int lct;
6651 
6652  assert(!(*cutoff));
6653 
6654  /* find responsible leaf for the lambda envelope */
6656  assert(leaf != NULL);
6657  assert(SCIPbtnodeIsLeaf(leaf));
6658 
6659  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6660  assert(leafdata != NULL);
6661  assert(!leafdata->intheta);
6662  assert(leafdata->duration > 0);
6663  assert(leafdata->est >= 0);
6664 
6665  /* check if the job has to be removed since its latest completion is to large */
6666  if( leafdata->est + leafdata->duration >= nodedata->lct )
6667  {
6668  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6669 
6670  /* the root might changed therefore we need to collect the new root node data */
6671  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6672  assert(rootdata != NULL);
6673 
6674  continue;
6675  }
6676 
6677  /* compute omega set */
6678  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6679 
6680  nelements = 0;
6681  est = INT_MAX;
6682  lct = INT_MIN;
6683  energy = 0;
6684 
6685  /* collect the omega set from theta set */
6686  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6687  assert(nelements > 0);
6688  assert(nelements < ncands);
6689 
6690  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6691 
6692  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6693  if( newest > lct )
6694  {
6695  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6696 
6697  /* analyze over load */
6698  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6699  conshdlrdata->usebdwidening, initialized, explanation) );
6700  (*cutoff) = TRUE;
6701 
6702  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6703  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6704  }
6705  else if( newest > 0 )
6706  {
6707  SCIP_Bool infeasible;
6708  SCIP_Bool tightened;
6709  INFERINFO inferinfo;
6710 
6711  if( propest )
6712  {
6713  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6714  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6715 
6716  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6717  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6718 
6719  if( inferInfoIsValid(inferinfo) )
6720  {
6721  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6722  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6723  }
6724  else
6725  {
6726  SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6727  TRUE, &infeasible, &tightened) );
6728  }
6729 
6730  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6732  }
6733  else
6734  {
6735  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6736  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6737 
6738  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6739  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6740 
6741  if( inferInfoIsValid(inferinfo) )
6742  {
6743  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6744  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6745  }
6746  else
6747  {
6748  SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6749  TRUE, &infeasible, &tightened) );
6750  }
6751 
6752  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6754  }
6755 
6756  /* adjust the earliest start time */
6757  if( tightened )
6758  {
6759  leafdata->est = newest;
6760  (*nchgbds)++;
6761  }
6762 
6763  if( infeasible )
6764  {
6765  /* initialize conflict analysis if conflict analysis is applicable */
6767  {
6768  int i;
6769 
6770  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6771 
6773 
6774  /* add lower and upper bound of variable which leads to the infeasibilty */
6775  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6776  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6777 
6778  if( explanation != NULL )
6779  explanation[leafdata->idx] = TRUE;
6780 
6781  /* add lower and upper bound of variable which lead to the infeasibilty */
6782  for( i = 0; i < nelements; ++i )
6783  {
6784  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6785  assert(nodedata != NULL);
6786 
6787  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6788  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6789 
6790  if( explanation != NULL )
6791  explanation[nodedata->idx] = TRUE;
6792  }
6793 
6794  (*initialized) = TRUE;
6795  }
6796 
6797  (*cutoff) = TRUE;
6798 
6799  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6800  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6801  }
6802  }
6803 
6804  /* free omegaset array */
6805  SCIPfreeBufferArray(scip, &omegaset);
6806 
6807  /* delete responsible leaf from lambda */
6808  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6809 
6810  /* the root might changed therefore we need to collect the new root node data */
6811  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6812  assert(rootdata != NULL);
6813  }
6814 
6815  /* move current job j from the theta set into the lambda set */
6816  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6817  }
6818 
6819  return SCIP_OKAY;
6820 }
6821 
6822 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6823  *
6824  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6825  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6826  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6827  */
6828 static
6830  SCIP* scip, /**< SCIP data structure */
6831  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6832  int nvars, /**< number of start time variables (activities) */
6833  SCIP_VAR** vars, /**< array of start time variables */
6834  int* durations, /**< array of durations */
6835  int* demands, /**< array of demands */
6836  int capacity, /**< cumulative capacity */
6837  int hmin, /**< left bound of time axis to be considered (including hmin) */
6838  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6839  SCIP_CONS* cons, /**< constraint which is propagated */
6840  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6841  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6842  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6843  int* nchgbds, /**< pointer to store the number of bound changes */
6844  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6845  )
6846 {
6847  SCIP_NODEDATA* nodedatas;
6848  SCIP_BTNODE** leaves;
6849  SCIP_BT* tree;
6850  int* nodedataidx;
6851 
6852  int totalenergy;
6853  int nnodedatas;
6854  int ninsertcands;
6855  int ncands;
6856 
6857  int shift;
6858  int idx = -1;
6859  int j;
6860 
6861  assert(scip != NULL);
6862  assert(cons != NULL);
6863  assert(initialized != NULL);
6864  assert(cutoff != NULL);
6865  assert(*cutoff == FALSE);
6866 
6867  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6868 
6869  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6870  SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6871  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6872 
6873  ncands = 0;
6874  totalenergy = 0;
6875 
6876  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6877 
6878  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6879  if( propest )
6880  shift = 0;
6881  else
6882  {
6883  shift = 0;
6884 
6885  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6886  * earliest start time propagation to handle the latest completion times
6887  */
6888  for( j = 0; j < nvars; ++j )
6889  {
6890  int lct;
6891 
6892  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6893  shift = MAX(shift, lct);
6894  }
6895  }
6896 
6897  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6898  * horizon
6899  */
6900  for( j = 0; j < nvars; ++j )
6901  {
6902  SCIP_NODEDATA* nodedata;
6903  SCIP_VAR* var;
6904  int duration;
6905  int leftadjust;
6906  int rightadjust;
6907  int energy;
6908  int est;
6909  int lct;
6910 
6911  var = vars[j];
6912  assert(var != NULL);
6913 
6914  duration = durations[j];
6915  assert(duration > 0);
6916 
6917  leftadjust = 0;
6918  rightadjust = 0;
6919 
6920  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6921  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6922 
6923  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6924  * effective horizon [hmin,hmax)
6925  */
6926  if( conshdlrdata->useadjustedjobs )
6927  {
6928  if( est < hmin )
6929  {
6930  leftadjust = (hmin - est);
6931  est = hmin;
6932  }
6933  if( lct > hmax )
6934  {
6935  rightadjust = (lct - hmax);
6936  lct = hmax;
6937  }
6938 
6939  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6940  * with the effective time horizon
6941  */
6942  if( duration - leftadjust - rightadjust <= 0 )
6943  continue;
6944  }
6945  else if( est < hmin || lct > hmax )
6946  continue;
6947 
6948  energy = demands[j] * (duration - leftadjust - rightadjust);
6949  assert(energy > 0);
6950 
6951  totalenergy += energy;
6952 
6953  /* flip earliest start time and latest completion time */
6954  if( !propest )
6955  {
6956  SCIPswapInts(&est, &lct);
6957 
6958  /* shift earliest start time and latest completion time */
6959  lct = shift - lct;
6960  est = shift - est;
6961  }
6962  else
6963  {
6964  /* shift earliest start time and latest completion time */
6965  lct = lct - shift;
6966  est = est - shift;
6967  }
6968  assert(est < lct);
6969  assert(est >= 0);
6970  assert(lct >= 0);
6971 
6972  /* create search node data */
6973  nodedata = &nodedatas[ncands];
6974  nodedataidx[ncands] = ncands;
6975  ++ncands;
6976 
6977  /* initialize search node data */
6978  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6979  nodedata->key = est + j / (2.0 * nvars);
6980  nodedata->var = var;
6981  nodedata->est = est;
6982  nodedata->lct = lct;
6983  nodedata->demand = demands[j];
6984  nodedata->duration = duration;
6985  nodedata->leftadjust = leftadjust;
6986  nodedata->rightadjust = rightadjust;
6987 
6988  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6989  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6990  * particular time interval [a,b] against the time interval [0,b].
6991  */
6992  nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
6993  nodedata->energytheta = energy;
6994  nodedata->enveloplambda = -1;
6995  nodedata->energylambda = -1;
6996 
6997  nodedata->idx = j;
6998  nodedata->intheta = TRUE;
6999  }
7000 
7001  nnodedatas = ncands;
7002 
7003  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
7004  SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
7005 
7006  ninsertcands = 0;
7007 
7008  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
7009  * the root envelop detects an overload
7010  */
7011  for( j = 0; j < ncands; ++j )
7012  {
7013  SCIP_BTNODE* leaf;
7014  SCIP_NODEDATA* rootdata;
7015 
7016  idx = nodedataidx[j];
7017 
7018  /* check if the new job opens a time window which size is so large that it offers more energy than the total
7019  * energy of all candidate jobs. If so we skip that one.
7020  */
7021  if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
7022  {
7023  /* set the earliest start time to minus one to mark that candidate to be not used */
7024  nodedatas[idx].est = -1;
7025  continue;
7026  }
7027 
7028  /* create search node */
7029  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
7030 
7031  /* insert new node into the theta set and updete the envelops */
7032  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
7033  assert(nnodedatas <= 2*nvars);
7034 
7035  /* move the inserted candidates together */
7036  leaves[ninsertcands] = leaf;
7037  ninsertcands++;
7038 
7039  assert(!SCIPbtIsEmpty(tree));
7040  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
7041  assert(rootdata != NULL);
7042 
7043  /* check if the theta set envelops exceeds the available capacity */
7044  if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
7045  {
7046  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
7047  (*cutoff) = TRUE;
7048 
7049  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7050  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7051 
7052  break;
7053  }
7054  }
7055 
7056  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7057  if( *cutoff )
7058  {
7059  int glbenery;
7060  int est;
7061  int lct;
7062 
7063  glbenery = 0;
7064  assert( 0 <= idx );
7065  est = nodedatas[idx].est;
7066  lct = nodedatas[idx].lct;
7067 
7068  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7069  * which led to an overload
7070  */
7071  for( j = j+1; j < ncands; ++j )
7072  {
7073  SCIP_NODEDATA* nodedata;
7074  int duration;
7075  int glbest;
7076  int glblct;
7077 
7078  idx = nodedataidx[j];
7079  nodedata = &nodedatas[idx];
7080  assert(nodedata != NULL);
7081 
7082  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7083 
7084  /* get latest start time */
7085  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7086  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7087 
7088  /* check if parts of the jobs run with the time window defined by the last inserted job */
7089  if( glbest < est )
7090  duration -= (est - glbest);
7091 
7092  if( glblct > lct )
7093  duration -= (glblct - lct);
7094 
7095  if( duration > 0 )
7096  {
7097  glbenery += nodedata->demand * duration;
7098 
7099  if( explanation != NULL )
7100  explanation[nodedata->idx] = TRUE;
7101  }
7102  }
7103 
7104  /* analyze the overload */
7105  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7106  conshdlrdata->usebdwidening, initialized, explanation) );
7107  }
7108  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7109  {
7110  /* if we have more than one job insterted and edge-finding should be performed we do it */
7111  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7112  propest, shift, initialized, explanation, nchgbds, cutoff) );
7113  }
7114 
7115  /* free theta tree */
7116  SCIPbtFree(&tree);
7117 
7118  /* free buffer arrays */
7119  SCIPfreeBufferArray(scip, &leaves);
7120  SCIPfreeBufferArray(scip, &nodedataidx);
7121  SCIPfreeBufferArray(scip, &nodedatas);
7122 
7123  return SCIP_OKAY;
7124 }
7125 
7126 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7127  *
7128  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7129  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7130  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7131  */
7132 static
7134  SCIP* scip, /**< SCIP data structure */
7135  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7136  int nvars, /**< number of start time variables (activities) */
7137  SCIP_VAR** vars, /**< array of start time variables */
7138  int* durations, /**< array of durations */
7139  int* demands, /**< array of demands */
7140  int capacity, /**< cumulative capacity */
7141  int hmin, /**< left bound of time axis to be considered (including hmin) */
7142  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7143  SCIP_CONS* cons, /**< constraint which is propagated */
7144  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7145  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7146  int* nchgbds, /**< pointer to store the number of bound changes */
7147  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7148  )
7149 {
7150  /* check if a cutoff was already detected */
7151  if( (*cutoff) )
7152  return SCIP_OKAY;
7153 
7154  /* check if at least the basic overload checking should be preformed */
7155  if( !conshdlrdata->efcheck )
7156  return SCIP_OKAY;
7157 
7158  /* check for overload, which may result in a cutoff */
7159  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7160  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7161 
7162  /* check if a cutoff was detected */
7163  if( (*cutoff) )
7164  return SCIP_OKAY;
7165 
7166  /* check if bound should be infer */
7167  if( !conshdlrdata->efinfer )
7168  return SCIP_OKAY;
7169 
7170  /* check for overload, which may result in a cutoff */
7171  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7172  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7173 
7174  return SCIP_OKAY;
7175 }
7176 
7177 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7178  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7179  * event points
7180  */
7181 static
7183  SCIP* scip, /**< SCIP data structure */
7184  int nvars, /**< number of start time variables (activities) */
7185  SCIP_VAR** vars, /**< array of start time variables */
7186  int* durations, /**< array of durations */
7187  int* demands, /**< array of demands */
7188  int capacity, /**< cumulative capacity */
7189  int hmin, /**< left bound of time axis to be considered (including hmin) */
7190  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7191  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7192  )
7193 {
7194  SCIP_VAR* var;
7195  int* starttimes; /* stores when each job is starting */
7196  int* endtimes; /* stores when each job ends */
7197  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7198  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7199 
7200  int lb;
7201  int ub;
7202  int freecapacity; /* remaining capacity */
7203  int curtime; /* point in time which we are just checking */
7204  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7205  int njobs;
7206  int j;
7207 
7208  assert(scip != NULL);
7209  assert(redundant != NULL);
7210 
7211  (*redundant) = TRUE;
7212 
7213  /* if no activities are associated with this cumulative then this constraint is redundant */
7214  if( nvars == 0 )
7215  return SCIP_OKAY;
7216 
7217  assert(vars != NULL);
7218 
7219  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7220  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7221  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7222  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7223 
7224  njobs = 0;
7225 
7226  /* assign variables, start and endpoints to arrays */
7227  for( j = 0; j < nvars; ++j )
7228  {
7229  assert(durations[j] > 0);
7230  assert(demands[j] > 0);
7231 
7232  var = vars[j];
7233  assert(var != NULL);
7234 
7235  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7236  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7237 
7238  /* check if jobs runs completely outside of the effective time horizon */
7239  if( lb >= hmax || ub + durations[j] <= hmin )
7240  continue;
7241 
7242  starttimes[njobs] = MAX(lb, hmin);
7243  startindices[njobs] = j;
7244 
7245  endtimes[njobs] = MIN(ub + durations[j], hmax);
7246  endindices[njobs] = j;
7247  assert(starttimes[njobs] <= endtimes[njobs]);
7248  njobs++;
7249  }
7250 
7251  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7252  SCIPsortIntInt(starttimes, startindices, njobs);
7253  SCIPsortIntInt(endtimes, endindices, njobs);
7254 
7255  endindex = 0;
7256  freecapacity = capacity;
7257 
7258  /* check each start point of a job whether the capacity is violated or not */
7259  for( j = 0; j < njobs; ++j )
7260  {
7261  curtime = starttimes[j];
7262 
7263  /* stop checking, if time point is above hmax */
7264  if( curtime >= hmax )
7265  break;
7266 
7267  /* subtract all capacity needed up to this point */
7268  freecapacity -= demands[startindices[j]];
7269  while( j+1 < njobs && starttimes[j+1] == curtime )
7270  {
7271  ++j;
7272  freecapacity -= demands[startindices[j]];
7273  }
7274 
7275  /* free all capacity usages of jobs the are no longer running */
7276  while( endtimes[endindex] <= curtime )
7277  {
7278  freecapacity += demands[endindices[endindex]];
7279  ++endindex;
7280  }
7281  assert(freecapacity <= capacity);
7282 
7283  /* check freecapacity to be smaller than zero */
7284  if( freecapacity < 0 && curtime >= hmin )
7285  {
7286  (*redundant) = FALSE;
7287  break;
7288  }
7289  } /*lint --e{850}*/
7290 
7291  /* free all buffer arrays */
7292  SCIPfreeBufferArray(scip, &endindices);
7293  SCIPfreeBufferArray(scip, &startindices);
7294  SCIPfreeBufferArray(scip, &endtimes);
7295  SCIPfreeBufferArray(scip, &starttimes);
7296 
7297  return SCIP_OKAY;
7298 }
7299 
7300 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7301  * completion time
7302  */
7303 static
7305  SCIP* scip, /**< SCIP data structure */
7306  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7307  SCIP_PROFILE* profile, /**< resource profile */
7308  int nvars, /**< number of variables (jobs) */
7309  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7310  int* durations, /**< array containing corresponding durations */
7311  int* demands, /**< array containing corresponding demands */
7312  int capacity, /**< cumulative capacity */
7313  int hmin, /**< left bound of time axis to be considered (including hmin) */
7314  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7315  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7316  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7317  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7318  )
7319 {
7320  int v;
7321 
7322  /* insert all cores */
7323  for( v = 0; v < nvars; ++v )
7324  {
7325  SCIP_VAR* var;
7326  SCIP_Bool infeasible;
7327  int duration;
7328  int demand;
7329  int begin;
7330  int end;
7331  int est;
7332  int lst;
7333  int pos;
7334 
7335  var = vars[v];
7336  assert(var != NULL);
7337  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7338  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7339 
7340  duration = durations[v];
7341  assert(duration > 0);
7342 
7343  demand = demands[v];
7344  assert(demand > 0);
7345 
7346  /* collect earliest and latest start time */
7347  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7348  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7349 
7350  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7351  if( lst + duration <= hmin || est >= hmax )
7352  continue;
7353 
7354  /* compute core interval w.r.t. effective time horizon */
7355  begin = MAX(hmin, lst);
7356  end = MIN(hmax, est + duration);
7357 
7358  /* check if a core exists */
7359  if( begin >= end )
7360  continue;
7361 
7362  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7363  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7364 
7365  /* insert the core into core resource profile (complexity O(log n)) */
7366  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7367 
7368  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7369  if( infeasible )
7370  {
7371  assert(begin <= SCIPprofileGetTime(profile, pos));
7372  assert(end > SCIPprofileGetTime(profile, pos));
7373 
7374  /* use conflict analysis to analysis the core insertion which was infeasible */
7375  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7376  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7377 
7378  if( explanation != NULL )
7379  explanation[v] = TRUE;
7380 
7381  (*cutoff) = TRUE;
7382 
7383  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7384  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7385 
7386  break;
7387  }
7388  }
7389 
7390  return SCIP_OKAY;
7391 }
7392 
7393 /** propagate the cumulative condition */
7394 static
7396  SCIP* scip, /**< SCIP data structure */
7397  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7398  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7399  int nvars, /**< number of start time variables (activities) */
7400  SCIP_VAR** vars, /**< array of start time variables */
7401  int* durations, /**< array of durations */
7402  int* demands, /**< array of demands */
7403  int capacity, /**< cumulative capacity */
7404  int hmin, /**< left bound of time axis to be considered (including hmin) */
7405  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7406  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7407  int* nchgbds, /**< pointer to store the number of bound changes */
7408  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7409  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7410  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7411  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7412  )
7413 {
7414  SCIP_PROFILE* profile;
7415 
7416  SCIP_RETCODE retcode = SCIP_OKAY;
7417 
7418  assert(nchgbds != NULL);
7419  assert(initialized != NULL);
7420  assert(cutoff != NULL);
7421  assert(!(*cutoff));
7422 
7423  /**@todo avoid always sorting the variable array */
7424 
7425  /* check if the constraint is redundant */
7426  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7427 
7428  if( *redundant )
7429  return SCIP_OKAY;
7430 
7431  /* create an empty resource profile for profiling the cores of the jobs */
7432  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7433 
7434  /* create core profile (compulsory parts) */
7435  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7436  initialized, explanation, cutoff), TERMINATE );
7437 
7438  /* propagate the job cores until nothing else can be detected */
7439  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7440  {
7441  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7442  nchgbds, initialized, explanation, cutoff), TERMINATE );
7443  }
7444 
7445  /* run edge finding propagator */
7446  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7447  {
7448  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7449  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7450  }
7451 
7452  /* run time-table edge-finding propagator */
7453  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7454  {
7455  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7456  nchgbds, initialized, explanation, cutoff), TERMINATE );
7457  }
7458  /* free resource profile */
7459 TERMINATE:
7460  SCIPprofileFree(&profile);
7461 
7462  return retcode;
7463 }
7464 
7465 /** propagate the cumulative constraint */
7466 static
7468  SCIP* scip, /**< SCIP data structure */
7469  SCIP_CONS* cons, /**< constraint to propagate */
7470  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7471  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7472  int* nchgbds, /**< pointer to store the number of bound changes */
7473  int* ndelconss, /**< pointer to store the number of deleted constraints */
7474  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7475  )
7476 {
7477  SCIP_CONSDATA* consdata;
7478  SCIP_Bool initialized;
7479  SCIP_Bool redundant;
7480  int oldnchgbds;
7481 
7482  assert(scip != NULL);
7483  assert(cons != NULL);
7484 
7485  consdata = SCIPconsGetData(cons);
7486  assert(consdata != NULL);
7487 
7488  oldnchgbds = *nchgbds;
7489  initialized = FALSE;
7490  redundant = FALSE;
7491 
7492  if( SCIPconsIsDeleted(cons) )
7493  {
7494  assert(SCIPinProbing(scip));
7495  return SCIP_OKAY;
7496  }
7497 
7498  /* if the constraint marked to be propagated, do nothing */
7499  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7500  return SCIP_OKAY;
7501 
7502  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7503  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7504  consdata->hmin, consdata->hmax, cons,
7505  nchgbds, &redundant, &initialized, NULL, cutoff) );
7506 
7507  if( redundant )
7508  {
7509  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7510  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7511 
7512  if( !SCIPinProbing(scip) )
7513  {
7514  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7515  (*ndelconss)++;
7516  }
7517  }
7518  else
7519  {
7520  if( initialized )
7521  {
7522  /* run conflict analysis since it was initialized */
7523  assert(*cutoff == TRUE);
7524  SCIPdebugMsg(scip, "start conflict analysis\n");
7525  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7526  }
7527 
7528  /* if successful, reset age of constraint */
7529  if( *cutoff || *nchgbds > oldnchgbds )
7530  {
7531  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7532  }
7533  else
7534  {
7535  /* mark the constraint to be propagated */
7536  consdata->propagated = TRUE;
7537  }
7538  }
7539 
7540  return SCIP_OKAY;
7541 }
7542 
7543 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7544  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7545  * be realize as domain reduction. Otherwise we do nothing
7546  */
7547 static
7549  SCIP* scip, /**< SCIP data structure */
7550  SCIP_VAR** vars, /**< problem variables */
7551  int nvars, /**< number of problem variables */
7552  int probingpos, /**< variable number to apply probing on */
7553  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7554  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7555  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7556  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7557  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7558  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7559  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7560  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7561  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7562  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7563  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7564  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7565  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7566  )
7567 {
7568  SCIP_VAR* var;
7569  SCIP_Bool tightened;
7570 
7571  assert(probingpos >= 0);
7572  assert(probingpos < nvars);
7573  assert(success != NULL);
7574  assert(cutoff != NULL);
7575 
7576  var = vars[probingpos];
7577  assert(var != NULL);
7578  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7579  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7580  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7581  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7582 
7583  (*success) = FALSE;
7584 
7585  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7586  return SCIP_OKAY;
7587 
7588  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7589  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7590  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7591 
7592  if( (*cutoff) )
7593  {
7594  /* note that cutoff may occur if presolving has not been executed fully */
7595  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7596 
7597  if( tightened )
7598  {
7599  (*success) =TRUE;
7600  (*nfixedvars)++;
7601  }
7602 
7603  return SCIP_OKAY;
7604  }
7605 
7606  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7607  * presolving has not been executed fully
7608  */
7609  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7610  {
7611  /* note that cutoff may occur if presolving has not been executed fully */
7612  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7613 
7614  if( tightened )
7615  {
7616  (*success) = TRUE;
7617  (*nfixedvars)++;
7618  }
7619 
7620  return SCIP_OKAY;
7621  }
7622 
7623  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7624  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7625  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7626 
7627  if( (*cutoff) )
7628  {
7629  /* note that cutoff may occur if presolving has not been executed fully */
7630  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7631 
7632  if( tightened )
7633  {
7634  (*success) =TRUE;
7635  (*nfixedvars)++;
7636  }
7637 
7638  return SCIP_OKAY;
7639  }
7640 
7641  return SCIP_OKAY;
7642 }
7643 
7644 /** is it possible, to round variable down w.r.t. objective function */
7645 static
7647  SCIP* scip, /**< SCIP data structure */
7648  SCIP_VAR* var, /**< problem variable */
7649  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7650  )
7651 {
7652  SCIP_Real objval;
7653  int scalar;
7654 
7655  assert(roundable != NULL);
7656 
7657  *roundable = TRUE;
7658 
7659  /* a fixed variable can be definition always be safely rounded */
7661  return SCIP_OKAY;
7662 
7663  /* in case the variable is not active we need to check the object coefficient of the active variable */
7664  if( !SCIPvarIsActive(var) )
7665  {
7666  SCIP_VAR* actvar;
7667  int constant;
7668 
7669  actvar = var;
7670 
7671  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7672  assert(scalar != 0);
7673 
7674  objval = scalar * SCIPvarGetObj(actvar);
7675  } /*lint !e438*/
7676  else
7677  {
7678  scalar = 1;
7679  objval = SCIPvarGetObj(var);
7680  }
7681 
7682  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7683  * (the transformed problem is always a minimization problem)
7684  *
7685  * @note that we need to check this condition w.r.t. active variable space
7686  */
7687  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7688  *roundable = FALSE;
7689 
7690  return SCIP_OKAY;
7691 }
7692 
7693 /** is it possible, to round variable up w.r.t. objective function */
7694 static
7696  SCIP* scip, /**< SCIP data structure */
7697  SCIP_VAR* var, /**< problem variable */
7698  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7699  )
7700 {
7701  SCIP_Real objval;
7702  int scalar;
7703 
7704  assert(roundable != NULL);
7705 
7706  *roundable = TRUE;
7707 
7708  /* a fixed variable can be definition always be safely rounded */
7710  return SCIP_OKAY;
7711 
7712  /* in case the variable is not active we need to check the object coefficient of the active variable */
7713  if( !SCIPvarIsActive(var) )
7714  {
7715  SCIP_VAR* actvar;
7716  int constant;
7717 
7718  actvar = var;
7719 
7720  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7721  assert(scalar != 0);
7722 
7723  objval = scalar * SCIPvarGetObj(actvar);
7724  } /*lint !e438*/
7725  else
7726  {
7727  scalar = 1;
7728  objval = SCIPvarGetObj(var);
7729  }
7730 
7731  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7732  * (the transformed problem is always a minimization problem)
7733  *
7734  * @note that we need to check this condition w.r.t. active variable space
7735  */
7736  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7737  *roundable = FALSE;
7738 
7739  return SCIP_OKAY;
7740 }
7741 
7742 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7743  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7744  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7745  * the only one locking this variable in the corresponding direction.
7746  */
7747 static
7749  SCIP* scip, /**< SCIP data structure */
7750  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7751  int nconss, /**< number of cumulative constraints */
7752  SCIP_Bool local, /**< use local bounds effective horizon? */
7753  int* alternativelbs, /**< alternative lower bounds */
7754  int* alternativeubs, /**< alternative lower bounds */
7755  int* downlocks, /**< number of constraints with down lock participating by the computation */
7756  int* uplocks /**< number of constraints with up lock participating by the computation */
7757  )
7758 {
7759  int nvars;
7760  int c;
7761  int v;
7762 
7763  for( c = 0; c < nconss; ++c )
7764  {
7765  SCIP_CONSDATA* consdata;
7766  SCIP_CONS* cons;
7767  SCIP_VAR* var;
7768  int hmin;
7769  int hmax;
7770 
7771  cons = conss[c];
7772  assert(cons != NULL);
7773 
7774  /* ignore constraints which are already deletet and those which are not check constraints */
7775  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7776  continue;
7777 
7778  consdata = SCIPconsGetData(cons);
7779  assert(consdata != NULL);
7780  assert(consdata->nvars > 1);
7781 
7782  /* compute the hmin and hmax */
7783  if( local )
7784  {
7785  SCIP_PROFILE* profile;
7786  SCIP_RETCODE retcode;
7787 
7788  /* create empty resource profile with infinity resource capacity */
7789  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7790 
7791  /* create worst case resource profile */
7792  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7793 
7794  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7795  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7796 
7797  /* free worst case profile */
7798  SCIPprofileFree(&profile);
7799 
7800  if( retcode != SCIP_OKAY )
7801  return retcode;
7802  }
7803  else
7804  {
7805  hmin = consdata->hmin;
7806  hmax = consdata->hmax;
7807  }
7808 
7809  consdata = SCIPconsGetData(cons);
7810  assert(consdata != NULL);
7811 
7812  nvars = consdata->nvars;
7813 
7814  for( v = 0; v < nvars; ++v )
7815  {
7816  int scalar;
7817  int constant;
7818  int idx;
7819 
7820  var = consdata->vars[v];
7821  assert(var != NULL);
7822 
7823  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7824  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7825 
7826  /* ignore variable locally fixed variables */
7827  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7828  continue;
7829 
7830  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7831  idx = SCIPvarGetProbindex(var);
7832  assert(idx >= 0);
7833 
7834  /* first check lower bound fixing */
7835  if( consdata->downlocks[v] )
7836  {
7837  int ect;
7838  int est;
7839 
7840  /* the variable has a down locked */
7841  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7842  ect = est + consdata->durations[v];
7843 
7844  if( ect <= hmin || hmin >= hmax )
7845  downlocks[idx]++;
7846  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7847  {
7848  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7849  downlocks[idx]++;
7850  }
7851  }
7852 
7853  /* second check upper bound fixing */
7854  if( consdata->uplocks[v] )
7855  {
7856  int duration;
7857  int lct;
7858  int lst;
7859 
7860  duration = consdata->durations[v];
7861 
7862  /* the variable has a up lock locked */
7863  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7864  lct = lst + duration;
7865 
7866  if( lst >= hmax || hmin >= hmax )
7867  uplocks[idx]++;
7868  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7869  {
7870  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7871  uplocks[idx]++;
7872  }
7873  }
7874  }
7875  }
7876 
7877  return SCIP_OKAY;
7878 }
7879 
7880 /** apply all fixings which are given by the alternative bounds */
7881 static
7883  SCIP* scip, /**< SCIP data structure */
7884  SCIP_VAR** vars, /**< array of active variables */
7885  int nvars, /**< number of active variables */
7886  int* alternativelbs, /**< alternative lower bounds */
7887  int* alternativeubs, /**< alternative lower bounds */
7888  int* downlocks, /**< number of constraints with down lock participating by the computation */
7889  int* uplocks, /**< number of constraints with up lock participating by the computation */
7890  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7891  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7892  )
7893 {
7894  SCIP_Real* downimpllbs;
7895  SCIP_Real* downimplubs;
7896  SCIP_Real* downproplbs;
7897  SCIP_Real* downpropubs;
7898  SCIP_Real* upimpllbs;
7899  SCIP_Real* upimplubs;
7900  SCIP_Real* upproplbs;
7901  SCIP_Real* uppropubs;
7902  int v;
7903 
7904  /* get temporary memory for storing probing results */
7905  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7906  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7907  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7908  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7909  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7910  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7911  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7912  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7913 
7914  for( v = 0; v < nvars; ++v )
7915  {
7916  SCIP_VAR* var;
7917  SCIP_Bool infeasible;
7918  SCIP_Bool fixed;
7919  SCIP_Bool roundable;
7920  int ub;
7921  int lb;
7922 
7923  var = vars[v];
7924  assert(var != NULL);
7925 
7926  /* ignore variables for which no alternative bounds have been computed */
7927  if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7928  continue;
7929 
7930  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7931  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7932 
7933  /* ignore fixed variables */
7934  if( ub - lb <= 0 )
7935  continue;
7936 
7937  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7938  {
7939  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7940 
7941  if( roundable )
7942  {
7943  if( alternativelbs[v] > ub )
7944  {
7945  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7946  assert(!infeasible);
7947  assert(fixed);
7948 
7949  (*nfixedvars)++;
7950 
7951  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7952  * constraints
7953  */
7954  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7955  }
7956  else
7957  {
7958  SCIP_Bool success;
7959 
7960  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7961  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7962  * infeasible we can apply the dual reduction; otherwise we do nothing
7963  */
7964  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7965  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7966  nfixedvars, &success, cutoff) );
7967 
7968  if( success )
7969  {
7970  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7971  }
7972  }
7973  }
7974  }
7975 
7976  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7977  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7978 
7979  /* ignore fixed variables */
7980  if( ub - lb <= 0 )
7981  continue;
7982 
7983  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7984  {
7985  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7986 
7987  if( roundable )
7988  {
7989  if( alternativeubs[v] < lb )
7990  {
7991  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7992  assert(!infeasible);
7993  assert(fixed);
7994 
7995  (*nfixedvars)++;
7996 
7997  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7998  * constraints
7999  */
8000  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8001  }
8002  else
8003  {
8004  SCIP_Bool success;
8005 
8006  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
8007  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
8008  * infeasible we can apply the dual reduction; otherwise we do nothing
8009  */
8010  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
8011  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
8012  nfixedvars, &success, cutoff) );
8013 
8014  if( success )
8015  {
8016  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8017  }
8018  }
8019  }
8020  }
8021  }
8022 
8023  /* free temporary memory */
8024  SCIPfreeBufferArray(scip, &uppropubs);
8025  SCIPfreeBufferArray(scip, &upproplbs);
8026  SCIPfreeBufferArray(scip, &upimplubs);
8027  SCIPfreeBufferArray(scip, &upimpllbs);
8028  SCIPfreeBufferArray(scip, &downpropubs);
8029  SCIPfreeBufferArray(scip, &downproplbs);
8030  SCIPfreeBufferArray(scip, &downimplubs);
8031  SCIPfreeBufferArray(scip, &downimpllbs);
8032 
8033  return SCIP_OKAY;
8034 }
8035 
8036 /** propagate all constraints together */
8037 static
8039  SCIP* scip, /**< SCIP data structure */
8040  SCIP_CONS** conss, /**< all cumulative constraint */
8041  int nconss, /**< number of cumulative constraints */
8042  SCIP_Bool local, /**< use local bounds effective horizon? */
8043  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
8044  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
8045  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
8046  )
8047 { /*lint --e{715}*/
8048  SCIP_VAR** vars;
8049  int* downlocks;
8050  int* uplocks;
8051  int* alternativelbs;
8052  int* alternativeubs;
8053  int oldnfixedvars;
8054  int nvars;
8055  int v;
8056 
8057  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8058  return SCIP_OKAY;
8059 
8060  nvars = SCIPgetNVars(scip);
8061  oldnfixedvars = *nfixedvars;
8062 
8063  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8064  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8065  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8066  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8067  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8068 
8069  /* initialize arrays */
8070  for( v = 0; v < nvars; ++v )
8071  {
8072  downlocks[v] = 0;
8073  uplocks[v] = 0;
8074  alternativelbs[v] = INT_MAX;
8075  alternativeubs[v] = INT_MIN;
8076  }
8077 
8078  /* compute alternative bounds */
8079  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8080 
8081  /* apply fixing which result of the alternative bounds directly */
8082  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8083  nfixedvars, cutoff) );
8084 
8085  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8086  {
8087  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8088  }
8089 
8090  /* free all buffers */
8091  SCIPfreeBufferArray(scip, &alternativeubs);
8092  SCIPfreeBufferArray(scip, &alternativelbs);
8093  SCIPfreeBufferArray(scip, &uplocks);
8094  SCIPfreeBufferArray(scip, &downlocks);
8095  SCIPfreeBufferArray(scip, &vars);
8096 
8097  return SCIP_OKAY;
8098 }
8099 
8100 /**@} */
8101 
8102 /**@name Linear relaxations
8103  *
8104  * @{
8105  */
8106 
8107 /** creates covering cuts for jobs violating resource constraints */
8108 static
8110  SCIP* scip, /**< SCIP data structure */
8111  SCIP_CONS* cons, /**< constraint to be checked */
8112  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8113  int time /**< at this point in time covering constraints are valid */
8114  )
8115 {
8116  SCIP_CONSDATA* consdata;
8117  SCIP_ROW* row;
8118  int* flexibleids;
8119  int* demands;
8120 
8121  char rowname[SCIP_MAXSTRLEN];
8122 
8123  int remainingcap;
8124  int smallcoversize; /* size of a small cover */
8125  int bigcoversize; /* size of a big cover */
8126  int nvars;
8127 
8128  int nflexible;
8129  int sumdemand; /* demand of all jobs up to a certain index */
8130  int j;
8131 
8132  assert(cons != NULL);
8133 
8134  /* get constraint data structure */
8135  consdata = SCIPconsGetData(cons);
8136  assert(consdata != NULL );
8137 
8138  nvars = consdata->nvars;
8139 
8140  /* sort jobs according to demands */
8141  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8142  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8143 
8144  nflexible = 0;
8145  remainingcap = consdata->capacity;
8146 
8147  /* get all jobs intersecting point 'time' with their bounds */
8148  for( j = 0; j < nvars; ++j )
8149  {
8150  int ub;
8151 
8152  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8153 
8154  /* only add jobs to array if they intersect with point 'time' */
8155  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8156  {
8157  /* if job is fixed, capacity has to be decreased */
8158  if( startvalues[j] == ub )
8159  {
8160  remainingcap -= consdata->demands[j];
8161  }
8162  else
8163  {
8164  demands[nflexible] = consdata->demands[j];
8165  flexibleids[nflexible] = j;
8166  ++nflexible;
8167  }
8168  }
8169  }
8170  assert(remainingcap >= 0);
8171 
8172  /* sort demands and job ids */
8173  SCIPsortIntInt(demands, flexibleids, nflexible);
8174 
8175  /*
8176  * version 1:
8177  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8178  * erzeuge cover constraint
8179  *
8180  */
8181 
8182  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8183  sumdemand = 0;
8184  j = 0;
8185 
8186  while( j < nflexible && sumdemand <= remainingcap )
8187  {
8188  sumdemand += demands[j];
8189  j++;
8190  }
8191 
8192  /* j jobs form a conflict, set coversize to 'j - 1' */
8193  bigcoversize = j-1;
8194  assert(sumdemand > remainingcap);
8195  assert(bigcoversize < nflexible);
8196 
8197  /* - create a row for all jobs and their binary variables.
8198  * - at most coversize many binary variables of jobs can be set to one
8199  */
8200 
8201  /* construct row name */
8202  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8203  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8204  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8205  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8206 
8207  for( j = 0; j < nflexible; ++j )
8208  {
8209  SCIP_VAR** binvars;
8210  SCIP_Real* vals;
8211  int nbinvars;
8212  int idx;
8213  int start;
8214  int end;
8215  int lb;
8216  int ub;
8217  int b;
8218 
8219  idx = flexibleids[j];
8220 
8221  /* get and add binvars into var array */
8222  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8223  assert(nbinvars != 0);
8224 
8225  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8226  assert(vals != NULL);
8227 
8228  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8229  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8230 
8231  /* compute start and finishing time */
8232  start = time - consdata->durations[idx] + 1;
8233  end = MIN(time, ub);
8234 
8235  /* add all neccessary binary variables */
8236  for( b = 0; b < nbinvars; ++b )
8237  {
8238  if( vals[b] < start || vals[b] < lb )
8239  continue;
8240 
8241  if( vals[b] > end )
8242  break;
8243 
8244  assert(binvars[b] != NULL);
8245  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8246  }
8247  }
8248 
8249  /* insert and release row */
8250  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8251 
8252  if( consdata->bcoverrowssize == 0 )
8253  {
8254  consdata->bcoverrowssize = 10;
8255  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8256  }
8257  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8258  {
8259  consdata->bcoverrowssize *= 2;
8260  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8261  }
8262 
8263  consdata->bcoverrows[consdata->nbcoverrows] = row;
8264  consdata->nbcoverrows++;
8265 
8266  /*
8267  * version 2:
8268  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8269  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8270  */
8271  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8272  sumdemand = 0;
8273  j = nflexible -1;
8274  while( sumdemand <= remainingcap )
8275  {
8276  assert(j >= 0);
8277  sumdemand += demands[j];
8278  j--;
8279  }
8280 
8281  smallcoversize = nflexible - (j + 1) - 1;
8282  while( j > 0 && demands[j] == demands[nflexible-1] )
8283  --j;
8284 
8285  assert(smallcoversize < nflexible);
8286 
8287  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8288  {
8289  /* construct row name */
8290  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8291  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8292  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8293  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8294 
8295  /* filter binary variables for each unfixed job */
8296  for( j = j + 1; j < nflexible; ++j )
8297  {
8298  SCIP_VAR** binvars;
8299  SCIP_Real* vals;
8300  int nbinvars;
8301  int idx;
8302  int start;
8303  int end;
8304  int lb;
8305  int ub;
8306  int b;
8307 
8308  idx = flexibleids[j];
8309 
8310  /* get and add binvars into var array */
8311  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8312  assert(nbinvars != 0);
8313 
8314  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8315  assert(vals != NULL);
8316 
8317  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8318  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8319 
8320  /* compute start and finishing time */
8321  start = time - consdata->durations[idx] + 1;
8322  end = MIN(time, ub);
8323 
8324  /* add all neccessary binary variables */
8325  for( b = 0; b < nbinvars; ++b )
8326  {
8327  if( vals[b] < start || vals[b] < lb )
8328  continue;
8329 
8330  if( vals[b] > end )
8331  break;
8332 
8333  assert(binvars[b] != NULL);
8334  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8335  }
8336  }
8337 
8338  /* insert and release row */
8339  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8340  if( consdata->scoverrowssize == 0 )
8341  {
8342  consdata->scoverrowssize = 10;
8343  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8344  }
8345  if( consdata->nscoverrows == consdata->scoverrowssize )
8346  {
8347  consdata->scoverrowssize *= 2;
8348  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8349  }
8350 
8351  consdata->scoverrows[consdata->nscoverrows] = row;
8352  consdata->nscoverrows++;
8353  }
8354 
8355  /* free buffer arrays */
8356  SCIPfreeBufferArray(scip, &flexibleids);
8357  SCIPfreeBufferArray(scip, &demands);
8358 
8359  return SCIP_OKAY;
8360 }
8361 
8362 /** method to construct cover cuts for all points in time */
8363 static
8365  SCIP* scip, /**< SCIP data structure */
8366  SCIP_CONS* cons /**< constraint to be separated */
8367  )
8368 {
8369  SCIP_CONSDATA* consdata;
8370 
8371  int* startvalues; /* stores when each job is starting */
8372  int* endvalues; /* stores when each job ends */
8373  int* startvaluessorted; /* stores when each job is starting */
8374  int* endvaluessorted; /* stores when each job ends */
8375  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8376  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8377 
8378  int nvars; /* number of jobs for this constraint */
8379  int freecapacity; /* remaining capacity */
8380  int curtime; /* point in time which we are just checking */
8381  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8382 
8383  int hmin;
8384  int hmax;
8385 
8386  int j;
8387  int t;
8388 
8389  assert(scip != NULL);
8390  assert(cons != NULL);
8391 
8392  consdata = SCIPconsGetData(cons);
8393  assert(consdata != NULL);
8394 
8395  /* if no activities are associated with this resource then this constraint is redundant */
8396  if( consdata->vars == NULL )
8397  return SCIP_OKAY;
8398 
8399  nvars = consdata->nvars;
8400  hmin = consdata->hmin;
8401  hmax = consdata->hmax;
8402 
8403  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8404  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8405  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8406  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8407  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8408  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8409 
8410  /* assign start and endpoints to arrays */
8411  for ( j = 0; j < nvars; ++j )
8412  {
8413  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8414  startvaluessorted[j] = startvalues[j];
8415 
8416  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8417  endvaluessorted[j] = endvalues[j];
8418 
8419  startindices[j] = j;
8420  endindices[j] = j;
8421  }
8422 
8423  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8424  * (and sort the indices in the same way) */
8425  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8426  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8427 
8428  endidx = 0;
8429  freecapacity = consdata->capacity;
8430 
8431  /* check each startpoint of a job whether the capacity is kept or not */
8432  for( j = 0; j < nvars; ++j )
8433  {
8434  curtime = startvaluessorted[j];
8435  if( curtime >= hmax )
8436  break;
8437 
8438  /* subtract all capacity needed up to this point */
8439  freecapacity -= consdata->demands[startindices[j]];
8440 
8441  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8442  {
8443  ++j;
8444  freecapacity -= consdata->demands[startindices[j]];
8445  }
8446 
8447  /* free all capacity usages of jobs the are no longer running */
8448  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8449  {
8450  freecapacity += consdata->demands[endindices[endidx]];
8451  ++endidx;
8452  }
8453 
8454  assert(freecapacity <= consdata->capacity);
8455  assert(endidx <= nvars);
8456 
8457  /* --> endindex - points to the next job which will finish
8458  * j - points to the last job that has been released
8459  */
8460 
8461  /* check freecapacity to be smaller than zero
8462  * then we will add cover constraints to the MIP
8463  */
8464  if( freecapacity < 0 && curtime >= hmin )
8465  {
8466  int nextprofilechange;
8467 
8468  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8469  if( j < nvars-1 )
8470  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8471  else
8472  nextprofilechange = endvaluessorted[endidx];
8473 
8474  nextprofilechange = MIN(nextprofilechange, hmax);
8475 
8476  for( t = curtime; t < nextprofilechange; ++t )
8477  {
8478  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8479 
8480  /* create covering constraint */
8481  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8482  }
8483  } /* end if freecapacity > 0 */
8484  } /*lint --e{850}*/
8485 
8486  consdata->covercuts = TRUE;
8487 
8488  /* free all buffer arrays */
8489  SCIPfreeBufferArray(scip, &endindices);
8490  SCIPfreeBufferArray(scip, &startindices);
8491  SCIPfreeBufferArray(scip, &endvaluessorted);
8492  SCIPfreeBufferArray(scip, &startvaluessorted);
8493  SCIPfreeBufferArray(scip, &endvalues);
8494  SCIPfreeBufferArray(scip, &startvalues);
8495 
8496  return SCIP_OKAY;
8497 }
8498 
8499 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8500  * constraint
8501  */
8502 static
8504  SCIP* scip, /**< SCIP data structure */
8505  SCIP_CONS* cons, /**< constraint to be checked */
8506  int* startindices, /**< permutation with rspect to the start times */
8507  int curtime, /**< current point in time */
8508  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8509  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8510  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8511  )
8512 {
8513  SCIP_CONSDATA* consdata;
8514  SCIP_VAR** binvars;
8515  int* coefs;
8516  int nbinvars;
8517  char name[SCIP_MAXSTRLEN];
8518  int capacity;
8519  int b;
8520 
8521  assert(nstarted > nfinished);
8522 
8523  consdata = SCIPconsGetData(cons);
8524  assert(consdata != NULL);
8525  assert(consdata->nvars > 0);
8526 
8527  capacity = consdata->capacity;
8528  assert(capacity > 0);
8529 
8530  nbinvars = 0;
8531  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8532 
8533  /* construct row name */
8534  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8535 
8536  if( cutsasconss )
8537  {
8538  SCIP_CONS* lincons;
8539 
8540  /* create knapsack constraint for the given time point */
8541  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8542  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8543 
8544  for( b = 0; b < nbinvars; ++b )
8545  {
8546  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8547  }
8548 
8549  /* add and release the new constraint */
8550  SCIP_CALL( SCIPaddCons(scip, lincons) );
8551  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8552  }
8553  else
8554  {
8555  SCIP_ROW* row;
8556 
8557  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8558  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8559 
8560  for( b = 0; b < nbinvars; ++b )
8561  {
8562  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8563  }
8564 
8565  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8566  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8567 
8568  if( consdata->demandrowssize == 0 )
8569  {
8570  consdata->demandrowssize = 10;
8571  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8572  }
8573  if( consdata->ndemandrows == consdata->demandrowssize )
8574  {
8575  consdata->demandrowssize *= 2;
8576  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8577  }
8578 
8579  consdata->demandrows[consdata->ndemandrows] = row;
8580  consdata->ndemandrows++;
8581  }
8582 
8583  SCIPfreeBufferArrayNull(scip, &binvars);
8584  SCIPfreeBufferArrayNull(scip, &coefs);
8585 
8586  return SCIP_OKAY;
8587 }
8588 
8589 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8590  * row
8591  */
8592 static
8594  SCIP* scip, /**< SCIP data structure */
8595  SCIP_CONS* cons, /**< constraint to be checked */
8596  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8597  )
8598 {
8599  SCIP_CONSDATA* consdata;
8600 
8601  int* starttimes; /* stores when each job is starting */
8602  int* endtimes; /* stores when each job ends */
8603  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8604  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8605 
8606  int nvars; /* number of activities for this constraint */
8607  int freecapacity; /* remaining capacity */
8608  int curtime; /* point in time which we are just checking */
8609  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8610 
8611  int hmin;
8612  int hmax;
8613 
8614  int j;
8615 
8616  assert(scip != NULL);
8617  assert(cons != NULL);
8618 
8619  consdata = SCIPconsGetData(cons);
8620  assert(consdata != NULL);
8621 
8622  nvars = consdata->nvars;
8623 
8624  /* if no activities are associated with this cumulative then this constraint is redundant */
8625  if( nvars == 0 )
8626  return SCIP_OKAY;
8627 
8628  assert(consdata->vars != NULL);
8629 
8630  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8631  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8632  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8633  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8634 
8635  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8636  SCIPconsGetName(cons), nvars);
8637 
8638  /* create event point arrays */
8639  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8640  starttimes, endtimes, startindices, endindices, FALSE);
8641 
8642  endindex = 0;
8643  freecapacity = consdata->capacity;
8644  hmin = consdata->hmin;
8645  hmax = consdata->hmax;
8646 
8647  /* check each startpoint of a job whether the capacity is kept or not */
8648  for( j = 0; j < nvars; ++j )
8649  {
8650  curtime = starttimes[j];
8651  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8652 
8653  if( curtime >= hmax )
8654  break;
8655 
8656  /* remove the capacity requirments for all job which start at the curtime */
8657  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8658 
8659  /* add the capacity requirments for all job which end at the curtime */
8660  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8661 
8662  assert(freecapacity <= consdata->capacity);
8663  assert(endindex <= nvars);
8664 
8665  /* endindex - points to the next job which will finish */
8666  /* j - points to the last job that has been released */
8667 
8668  /* if free capacity is smaller than zero, then add rows to the LP */
8669  if( freecapacity < 0 && curtime >= hmin )
8670  {
8671  int nextstarttime;
8672  int t;
8673 
8674  /* step forward until next job is released and see whether capacity constraint is met or not */
8675  if( j < nvars-1 )
8676  nextstarttime = starttimes[j+1];
8677  else
8678  nextstarttime = endtimes[nvars-1];
8679 
8680  nextstarttime = MIN(nextstarttime, hmax);
8681 
8682  /* create capacity restriction row for current event point */
8683  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8684 
8685  /* create for all points in time between the current event point and next start event point a row if the free
8686  * capacity is still smaller than zero */
8687  for( t = curtime+1 ; t < nextstarttime; ++t )
8688  {
8689  /* add the capacity requirments for all job which end at the curtime */
8690  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8691 
8692  if( freecapacity < 0 )
8693  {
8694  /* add constraint */
8695  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8696 
8697  /* create capacity restriction row */
8698  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8699  }
8700  else
8701  break;
8702  }
8703  }
8704  } /*lint --e{850}*/
8705 
8706  /* free all buffer arrays */
8707  SCIPfreeBufferArray(scip, &endindices);
8708  SCIPfreeBufferArray(scip, &startindices);
8709  SCIPfreeBufferArray(scip, &endtimes);
8710  SCIPfreeBufferArray(scip, &starttimes);
8711 
8712  return SCIP_OKAY;
8713 }
8714 
8715 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8716  * capacity is larger than the capacity of the cumulative constraint
8717  * - for each necessary point in time:
8718  *
8719  * sum_j sum_t demand_j * x_{j,t} <= capacity
8720  *
8721  * where x(j,t) is the binary variables of job j at time t
8722  */
8723 static
8725  SCIP* scip, /**< SCIP data structure */
8726  SCIP_CONS* cons, /**< cumulative constraint */
8727  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8728  )
8729 {
8730  SCIP_CONSDATA* consdata;
8731 
8732  consdata = SCIPconsGetData(cons);
8733  assert(consdata != NULL);
8734  assert(consdata->demandrows == NULL);
8735  assert(consdata->ndemandrows == 0);
8736 
8737  /* collect the linking constraints */
8738  if( consdata->linkingconss == NULL )
8739  {
8740  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8741  }
8742 
8743  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8744 
8745  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8746  if( cutsasconss )
8747  {
8748  if( SCIPconsIsInitial(cons) )
8749  {
8750  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8751  }
8752  if( SCIPconsIsSeparated(cons) )
8753  {
8754  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8755  }
8756  if( SCIPconsIsEnforced(cons) )
8757  {
8758  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8759  }
8760  }
8761 
8762  return SCIP_OKAY;
8763 }
8764 
8765 /** adds linear relaxation of cumulative constraint to the LP */
8766 static
8768  SCIP* scip, /**< SCIP data structure */
8769  SCIP_CONS* cons, /**< cumulative constraint */
8770  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8771  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8772  )
8773 {
8774  SCIP_CONSDATA* consdata;
8775  int r;
8776 
8777  consdata = SCIPconsGetData(cons);
8778  assert(consdata != NULL);
8779 
8780  if( consdata->demandrows == NULL )
8781  {
8782  assert(consdata->ndemandrows == 0);
8783 
8784  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8785 
8786  return SCIP_OKAY;
8787  }
8788 
8789  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8790  {
8791  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8792  {
8793  assert(consdata->demandrows[r] != NULL);
8794  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8795  }
8796  }
8797 
8798  return SCIP_OKAY;
8799 }
8800 
8801 /** checks constraint for violation, and adds it as a cut if possible */
8802 static
8804  SCIP* scip, /**< SCIP data structure */
8805  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8806  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8807  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8808  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8809  )
8810 { /*lint --e{715}*/
8811  SCIP_CONSDATA* consdata;
8812  int ncuts;
8813  int r;
8814 
8815  assert(scip != NULL);
8816  assert(cons != NULL);
8817  assert(separated != NULL);
8818  assert(cutoff != NULL);
8819 
8820  *separated = FALSE;
8821  *cutoff = FALSE;
8822 
8823  consdata = SCIPconsGetData(cons);
8824  assert(consdata != NULL);
8825 
8826  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8827 
8828  if( consdata->demandrows == NULL )
8829  {
8830  assert(consdata->ndemandrows == 0);
8831 
8832  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8833 
8834  return SCIP_OKAY;
8835  }
8836 
8837  ncuts = 0;
8838 
8839  /* check each row that is not contained in LP */
8840  for( r = 0; r < consdata->ndemandrows; ++r )
8841  {
8842  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8843  {
8844  SCIP_Real feasibility;
8845 
8846  if( sol != NULL )
8847  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8848  else
8849  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8850 
8851  if( SCIPisFeasNegative(scip, feasibility) )
8852  {
8853  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8854  if ( *cutoff )
8855  {
8856  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8857  return SCIP_OKAY;
8858  }
8859  *separated = TRUE;
8860  ncuts++;
8861  }
8862  }
8863  }
8864 
8865  if( ncuts > 0 )
8866  {
8867  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8868 
8869  /* if successful, reset age of constraint */
8870  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8871  (*separated) = TRUE;
8872  }
8873 
8874  return SCIP_OKAY;
8875 }
8876 
8877 /** checks constraint for violation, and adds it as a cut if possible */
8878 static
8880  SCIP* scip, /**< SCIP data structure */
8881  SCIP_CONS* cons, /**< logic or constraint to be separated */
8882  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8883  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8884  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8885  )
8886 {
8887  SCIP_CONSDATA* consdata;
8888  SCIP_ROW* row;
8889  SCIP_Real minfeasibility;
8890  int r;
8891 
8892  assert(scip != NULL);
8893  assert(cons != NULL);
8894  assert(separated != NULL);
8895  assert(cutoff != NULL);
8896 
8897  *separated = FALSE;
8898  *cutoff = FALSE;
8899 
8900  consdata = SCIPconsGetData(cons);
8901  assert(consdata != NULL);
8902 
8903  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8904 
8905  /* collect the linking constraints */
8906  if( consdata->linkingconss == NULL )
8907  {
8908  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8909  }
8910 
8911  if( !consdata->covercuts )
8912  {
8913  SCIP_CALL( createCoverCuts(scip, cons) );
8914  }
8915 
8916  row = NULL;
8917  minfeasibility = SCIPinfinity(scip);
8918 
8919  /* check each row of small covers that is not contained in LP */
8920  for( r = 0; r < consdata->nscoverrows; ++r )
8921  {
8922  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8923  {
8924  SCIP_Real feasibility;
8925 
8926  assert(consdata->scoverrows[r] != NULL);
8927  if( sol != NULL )
8928  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8929  else
8930  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8931 
8932  if( minfeasibility > feasibility )
8933  {
8934  minfeasibility = feasibility;
8935  row = consdata->scoverrows[r];
8936  }
8937  }
8938  }
8939 
8940  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8941 
8942  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8943  {
8944  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8945  SCIPconsGetName(cons), minfeasibility);
8946 
8947  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8948  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8949  if ( *cutoff )
8950  return SCIP_OKAY;
8951  (*separated) = TRUE;
8952  }
8953 
8954  minfeasibility = SCIPinfinity(scip);
8955  row = NULL;
8956 
8957  /* check each row of small covers that is not contained in LP */
8958  for( r = 0; r < consdata->nbcoverrows; ++r )
8959  {
8960  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8961  {
8962  SCIP_Real feasibility;
8963 
8964  assert(consdata->bcoverrows[r] != NULL);
8965  if( sol != NULL )
8966  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8967  else
8968  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8969 
8970  if( minfeasibility > feasibility )
8971  {
8972  minfeasibility = feasibility;
8973  row = consdata->bcoverrows[r];
8974  }
8975  }
8976  }
8977 
8978  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8979 
8980  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8981  {
8982  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8983  SCIPconsGetName(cons), minfeasibility);
8984 
8985  assert(row != NULL);
8986  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8987  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8988  if ( *cutoff )
8989  return SCIP_OKAY;
8990  (*separated) = TRUE;
8991  }
8992 
8993  return SCIP_OKAY;
8994 }
8995 
8996 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8997 static
8999  SCIP* scip, /**< SCIP data structure */
9000  SCIP_CONS* cons, /**< constraint to be checked */
9001  int* startindices, /**< permutation with rspect to the start times */
9002  int curtime, /**< current point in time */
9003  int nstarted, /**< number of jobs that start before the curtime or at curtime */
9004  int nfinished, /**< number of jobs that finished before curtime or at curtime */
9005  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
9006  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9007  )
9008 {
9009  SCIP_CONSDATA* consdata;
9010  char name[SCIP_MAXSTRLEN];
9011  int lhs; /* left hand side of constraint */
9012 
9013  SCIP_VAR** activevars;
9014  SCIP_ROW* row;
9015 
9016  int v;
9017 
9018  assert(nstarted > nfinished);
9019 
9020  consdata = SCIPconsGetData(cons);
9021  assert(consdata != NULL);
9022  assert(consdata->nvars > 0);
9023 
9024  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
9025 
9026  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
9027 
9028  if( lower )
9029  {
9030  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
9031 
9032  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
9033  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9034  }
9035  else
9036  {
9037  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
9038  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
9039  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9040  }
9041 
9042  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
9043 
9044  for( v = 0; v < nstarted - nfinished; ++v )
9045  {
9046  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9047  }
9048 
9049  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
9050  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9051 
9052  SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9053 
9054  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9055 
9056  /* free buffers */
9057  SCIPfreeBufferArrayNull(scip, &activevars);
9058 
9059  return SCIP_OKAY;
9060 }
9061 
9062 /** checks constraint for violation, and adds it as a cut if possible */
9063 static
9065  SCIP* scip, /**< SCIP data structure */
9066  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9067  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9068  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9069  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9070  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9071  )
9072 {
9073  SCIP_CONSDATA* consdata;
9074 
9075  int* starttimes; /* stores when each job is starting */
9076  int* endtimes; /* stores when each job ends */
9077  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9078  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9079 
9080  int nvars; /* number of activities for this constraint */
9081  int freecapacity; /* remaining capacity */
9082  int curtime; /* point in time which we are just checking */
9083  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9084 
9085  int hmin;
9086  int hmax;
9087  int j;
9088 
9089  assert(scip != NULL);
9090  assert(cons != NULL);
9091 
9092  consdata = SCIPconsGetData(cons);
9093  assert(consdata != NULL);
9094 
9095  nvars = consdata->nvars;
9096 
9097  /* if no activities are associated with this cumulative then this constraint is redundant */
9098  if( nvars <= 1 )
9099  return SCIP_OKAY;
9100 
9101  assert(consdata->vars != NULL);
9102 
9103  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9104  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9105  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9106  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9107 
9108  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9109  SCIPconsGetName(cons), nvars);
9110 
9111  /* create event point arrays */
9112  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9113 
9114  /* now nvars might be smaller than before! */
9115 
9116  endindex = 0;
9117  freecapacity = consdata->capacity;
9118  hmin = consdata->hmin;
9119  hmax = consdata->hmax;
9120 
9121  /* check each startpoint of a job whether the capacity is kept or not */
9122  for( j = 0; j < nvars && !(*cutoff); ++j )
9123  {
9124  curtime = starttimes[j];
9125 
9126  if( curtime >= hmax )
9127  break;
9128 
9129  /* remove the capacity requirements for all job which start at the curtime */
9130  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9131 
9132  /* add the capacity requirments for all job which end at the curtime */
9133  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9134 
9135  assert(freecapacity <= consdata->capacity);
9136  assert(endindex <= nvars);
9137 
9138  /* endindex - points to the next job which will finish */
9139  /* j - points to the last job that has been released */
9140 
9141  /* if free capacity is smaller than zero, then add rows to the LP */
9142  if( freecapacity < 0 && curtime >= hmin)
9143  {
9144  /* create capacity restriction row for current event point */
9145  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9146  *separated = TRUE;
9147  }
9148  } /*lint --e{850}*/
9149 
9150  /* free all buffer arrays */
9151  SCIPfreeBufferArray(scip, &endindices);
9152  SCIPfreeBufferArray(scip, &startindices);
9153  SCIPfreeBufferArray(scip, &endtimes);
9154  SCIPfreeBufferArray(scip, &starttimes);
9155 
9156  return SCIP_OKAY;
9157 }
9158 
9159 /**@} */
9160 
9161 
9162 /**@name Presolving
9163  *
9164  * @{
9165  */
9166 
9167 #ifndef NDEBUG
9168 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9169  * correct
9170  */
9171 static
9173  SCIP* scip, /**< SCIP data structure */
9174  SCIP_CONS* cons /**< constraint to be checked */
9175  )
9176 {
9177  SCIP_CONSDATA* consdata;
9178  int capacity;
9179  int nvars;
9180  int j;
9181 
9182  assert(scip != NULL);
9183  assert(cons != NULL);
9184 
9185  consdata = SCIPconsGetData(cons);
9186  assert(consdata != NULL);
9187 
9188  nvars = consdata->nvars;
9189 
9190  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9191  if( nvars <= 1 )
9192  return TRUE;
9193 
9194  assert(consdata->vars != NULL);
9195  capacity = consdata->capacity;
9196 
9197  /* check each activity: if demand is larger than capacity the problem is infeasible */
9198  for ( j = 0; j < nvars; ++j )
9199  {
9200  if( consdata->demands[j] > capacity )
9201  return FALSE;
9202  }
9203 
9204  return TRUE;
9205 }
9206 #endif
9207 
9208 /** delete constraint if it consists of at most one job
9209  *
9210  * @todo this method needs to be adjusted w.r.t. effective horizon
9211  */
9212 static
9214  SCIP* scip, /**< SCIP data structure */
9215  SCIP_CONS* cons, /**< constraint to propagate */
9216  int* ndelconss, /**< pointer to store the number of deleted constraints */
9217  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9218  )
9219 {
9220  SCIP_CONSDATA* consdata;
9221 
9222  assert(scip != NULL);
9223  assert(cons != NULL);
9224 
9225  consdata = SCIPconsGetData(cons);
9226  assert(consdata != NULL);
9227 
9228  if( consdata->nvars == 0 )
9229  {
9230  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9231 
9232  SCIP_CALL( SCIPdelCons(scip, cons) );
9233  (*ndelconss)++;
9234  }
9235  else if( consdata->nvars == 1 )
9236  {
9237  if( consdata->demands[0] > consdata->capacity )
9238  (*cutoff) = TRUE;
9239  else
9240  {
9241  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9242 
9243  SCIP_CALL( SCIPdelCons(scip, cons) );
9244  (*ndelconss)++;
9245  }
9246  }
9247 
9248  return SCIP_OKAY;
9249 }
9250 
9251 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9252  * this is done in the SCIP_DECL_CONSINITPRE() callback
9253  */
9254 static
9256  SCIP* scip, /**< SCIP data structure */
9257  SCIP_CONS* cons /**< constraint to propagate */
9258  )
9259 {
9260  SCIP_CONSDATA* consdata;
9261  SCIP_VAR* var;
9262  int demand;
9263  int duration;
9264  int hmin;
9265  int hmax;
9266  int est;
9267  int lct;
9268  int j;
9269 
9270  assert(scip != NULL);
9271  assert(cons != NULL);
9272 
9273  consdata = SCIPconsGetData(cons);
9274  assert(consdata != NULL);
9275 
9276  hmin = consdata->hmin;
9277  hmax = consdata->hmax;
9278 
9279  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9280  SCIPconsGetName(cons), hmin, hmax);
9281 
9282  for( j = consdata->nvars-1; j >= 0; --j )
9283  {
9284  var = consdata->vars[j];
9285  demand = consdata->demands[j];
9286  duration = consdata->durations[j];
9287 
9288  /* earliest completion time (ect) and latest start time (lst) */
9289  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9290  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9291 
9292  if( demand == 0 || duration == 0 )
9293  {
9294  /* jobs with zero demand or zero duration can be removed */
9295  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9296  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9297 
9298  /* remove variable form constraint */
9299  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9300  }
9301  else if( est >= hmax || lct <= hmin )
9302  {
9303  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9304  SCIPvarGetName(var), est, lct - duration, duration);
9305 
9306  /* delete variable at the given position */
9307  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9308 
9309  /* for the statistic we count the number of jobs which are irrelevant */
9310  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9311  }
9312  }
9313 
9314  return SCIP_OKAY;
9315 }
9316 
9317 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9318 static
9320  SCIP* scip, /**< SCIP data structure */
9321  SCIP_CONSDATA* consdata, /**< constraint data */
9322  int pos, /**< position of job in the consdata */
9323  int* nchgbds, /**< pointer to store the number of changed bounds */
9324  int* naddconss, /**< pointer to store the number of added constraints */
9325  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9326  )
9327 {
9328  SCIP_VAR* var;
9329  SCIP_Bool tightened;
9330  int duration;
9331  int ect;
9332  int lst;
9333 
9334  assert(scip != NULL);
9335 
9336  /* zero energy jobs should be removed already */
9337  assert(consdata->durations[pos] > 0);
9338  assert(consdata->demands[pos] > 0);
9339 
9340  var = consdata->vars[pos];
9341  assert(var != NULL);
9342  duration = consdata->durations[pos];
9343 
9344  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9345  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9346  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9347 
9348  /* earliest completion time (ect) and latest start time (lst) */
9349  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9350  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9351 
9352  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9353  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9354  return SCIP_OKAY;
9355 
9356  if( ect > consdata->hmin && lst < consdata->hmax )
9357  {
9358  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9359  *cutoff = TRUE;
9360  }
9361  else if( lst < consdata->hmax )
9362  {
9363  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9364  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9365  assert(tightened);
9366  assert(!(*cutoff));
9367  (*nchgbds)++;
9368  }
9369  else if( ect > consdata->hmin )
9370  {
9371  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9372  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9373  assert(tightened);
9374  assert(!(*cutoff));
9375  (*nchgbds)++;
9376  }
9377  else
9378  {
9379  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9380  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9381  *
9382  * (var <= hmin - duration) /\ (var >= hmax)
9383  */
9384  SCIP_CONS* cons;
9385 
9386  SCIP_VAR* vartuple[2];
9387  SCIP_BOUNDTYPE boundtypetuple[2];
9388  SCIP_Real boundtuple[2];
9389 
9390  char name[SCIP_MAXSTRLEN];
9391  int leftbound;
9392  int rightbound;
9393 
9394  leftbound = consdata->hmin - duration;
9395  rightbound = consdata->hmax;
9396 
9397  /* allocate temporary memory for arrays */
9398  vartuple[0] = var;
9399  vartuple[1] = var;
9400  boundtuple[0] = (SCIP_Real)leftbound;
9401  boundtuple[1] = (SCIP_Real)rightbound;
9402  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9403  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9404 
9405  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9406  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9407 
9408  /* create and add bounddisjunction constraint */
9409  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9410  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9411 
9412  SCIPdebugPrintCons(scip, cons, NULL);
9413 
9414  /* add and release the new constraint */
9415  SCIP_CALL( SCIPaddCons(scip, cons) );
9416  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9417  (*naddconss)++;
9418  }
9419 
9420  return SCIP_OKAY;
9421 }
9422 
9423 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9424 static
9426  SCIP* scip, /**< SCIP data structure */
9427  SCIP_CONS* cons, /**< constraint */
9428  int* nchgbds, /**< pointer to store the number of changed bounds */
9429  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9430  int* naddconss, /**< pointer to store the number of added constraints */
9431  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9432  )
9433 {
9434  SCIP_CONSDATA* consdata;
9435  int capacity;
9436  int j;
9437 
9438  consdata = SCIPconsGetData(cons);
9439  assert(consdata != NULL);
9440 
9441  /* if a cutoff was already detected just return */
9442  if( *cutoff )
9443  return SCIP_OKAY;
9444 
9445  capacity = consdata->capacity;
9446 
9447  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9448  {
9449  if( consdata->demands[j] > capacity )
9450  {
9451  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9452 
9453  /* remove variable form constraint */
9454  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9455  (*nchgcoefs)++;
9456  }
9457  }
9458 
9459  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9460 
9461  return SCIP_OKAY;
9462 }
9463 
9464 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9465 static
9467  SCIP* scip, /**< SCIP data structure */
9468  SCIP_VAR* var, /**< integer variable to fix */
9469  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9470  int* nfixedvars /**< pointer to store the number fixed variables */
9471  )
9472 {
9473  SCIP_Bool infeasible;
9474  SCIP_Bool tightened;
9475  SCIP_Bool roundable;
9476 
9477  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9478  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9479  */
9480  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9481  return SCIP_OKAY;
9482 
9483  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9484  * handler is the only one locking that variable up
9485  */
9486  assert(uplock == TRUE || uplock == FALSE);
9487  assert((int)TRUE == 1); /*lint !e506*/
9488  assert((int)FALSE == 0); /*lint !e506*/
9489 
9490  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9491  return SCIP_OKAY;
9492 
9493  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9494 
9495  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9496  * (the transformed problem is always a minimization problem)
9497  */
9498  if( !roundable )
9499  return SCIP_OKAY;
9500 
9501  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9503 
9504  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9505  assert(!infeasible);
9506 
9507  if( tightened )
9508  {
9509  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9510  (*nfixedvars)++;
9511  }
9512 
9513  return SCIP_OKAY;
9514 }
9515 
9516 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9517 static
9519  SCIP* scip, /**< SCIP data structure */
9520  SCIP_VAR* var, /**< integer variable to fix */
9521  SCIP_Bool downlock, /**< has the variable a down lock */
9522  int* nfixedvars /**< pointer to store the number fixed variables */
9523  )
9524 {
9525  SCIP_Bool infeasible;
9526  SCIP_Bool tightened;
9527  SCIP_Bool roundable;
9528 
9529  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9530  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9531  */
9532  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9533  return SCIP_OKAY;
9534 
9535  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9536  * handler is the only one locking that variable down
9537  */
9538  assert(downlock == TRUE || downlock == FALSE);
9539  assert((int)TRUE == 1); /*lint !e506*/
9540  assert((int)FALSE == 0); /*lint !e506*/
9541 
9542  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9543  return SCIP_OKAY;
9544 
9545  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9546 
9547  /* is it possible, to round variable down w.r.t. objective function? */
9548  if( !roundable )
9549  return SCIP_OKAY;
9550 
9551  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9552  assert(!infeasible);
9553 
9554  if( tightened )
9555  {
9556  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9557  (*nfixedvars)++;
9558  }
9559 
9560  return SCIP_OKAY;
9561 }
9562 
9563 /** normalize cumulative condition */
9564 static
9566  SCIP* scip, /**< SCIP data structure */
9567  int nvars, /**< number of start time variables (activities) */
9568  int* demands, /**< array of demands */
9569  int* capacity, /**< pointer to store the changed cumulative capacity */
9570  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9571  int* nchgsides /**< pointer to count number of side changes */
9572  )
9573 { /*lint --e{715}*/
9574  SCIP_Longint gcd;
9575  int mindemand1;
9576  int mindemand2;
9577  int v;
9578 
9579  if( *capacity == 1 || nvars <= 1 )
9580  return;
9581 
9582  assert(demands[nvars-1] <= *capacity);
9583  assert(demands[nvars-2] <= *capacity);
9584 
9585  gcd = (SCIP_Longint)demands[nvars-1];
9586  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9587  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9588 
9589  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9590  {
9591  assert(mindemand1 <= mindemand2);
9592  assert(demands[v] <= *capacity);
9593 
9594  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9595 
9596  if( mindemand1 > demands[v] )
9597  {
9598  mindemand2 = mindemand1;
9599  mindemand1 = demands[v];
9600  }
9601  else if( mindemand2 > demands[v] )
9602  mindemand2 = demands[v];
9603  }
9604 
9605  if( mindemand1 + mindemand2 > *capacity )
9606  {
9607  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9608 
9609  for( v = 0; v < nvars; ++v )
9610  demands[v] = 1;
9611 
9612  (*capacity) = 1;
9613 
9614  (*nchgcoefs) += nvars;
9615  (*nchgsides)++;
9616  }
9617  else if( gcd >= 2 )
9618  {
9619  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9620 
9621  for( v = 0; v < nvars; ++v )
9622  demands[v] /= (int) gcd;
9623 
9624  (*capacity) /= (int) gcd;
9625 
9626  (*nchgcoefs) += nvars;
9627  (*nchgsides)++;
9628  }
9629 }
9630 
9631 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9632  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9633  * capacity since in that case none of the jobs can run in parallel
9634  */
9635 static
9636 void normalizeDemands(
9637  SCIP* scip, /**< SCIP data structure */
9638  SCIP_CONS* cons, /**< cumulative constraint */
9639  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9640  int* nchgsides /**< pointer to count number of side changes */
9641  )
9642 {
9643  SCIP_CONSDATA* consdata;
9644  int capacity;
9645 
9646  assert(nchgcoefs != NULL);
9647  assert(nchgsides != NULL);
9648  assert(!SCIPconsIsModifiable(cons));
9649 
9650  consdata = SCIPconsGetData(cons);
9651  assert(consdata != NULL);
9652 
9653  if( consdata->normalized )
9654  return;
9655 
9656  capacity = consdata->capacity;
9657 
9658  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9659 
9660  normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9661 
9662  consdata->normalized = TRUE;
9663 
9664  if( capacity > consdata->capacity )
9665  consdata->varbounds = FALSE;
9666 }
9667 
9668 /** computes for the given cumulative condition the effective horizon */
9669 static
9671  SCIP* scip, /**< SCIP data structure */
9672  int nvars, /**< number of variables (jobs) */
9673  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9674  int* durations, /**< array containing corresponding durations */
9675  int* demands, /**< array containing corresponding demands */
9676  int capacity, /**< available cumulative capacity */
9677  int* hmin, /**< pointer to store the left bound of the effective horizon */
9678  int* hmax, /**< pointer to store the right bound of the effective horizon */
9679  int* split /**< point were the cumulative condition can be split */
9680  )
9681 {
9682  SCIP_PROFILE* profile;
9683 
9684  /* create empty resource profile with infinity resource capacity */
9685  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9686 
9687  /* create worst case resource profile */
9688  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9689 
9690  /* print resource profile in if SCIP_DEBUG is defined */
9691  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9692 
9693  /* computes the first time point where the resource capacity can be violated */
9694  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9695 
9696  /* computes the first time point where the resource capacity is satisfied for sure */
9697  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9698 
9699  (*split) = (*hmax);
9700 
9701  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9702  {
9703  int* timepoints;
9704  int* loads;
9705  int ntimepoints;
9706  int t;
9707 
9708  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9709  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9710  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9711  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9712  * explain the certain "old" bound changes
9713  */
9714 
9715  /* search for time points */
9716  ntimepoints = SCIPprofileGetNTimepoints(profile);
9717  timepoints = SCIPprofileGetTimepoints(profile);
9718  loads = SCIPprofileGetLoads(profile);
9719 
9720  /* 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 */
9721  for( t = 0; t < ntimepoints; ++t )
9722  {
9723  /* ignore all time points before the effective horizon */
9724  if( timepoints[t] <= *hmin )
9725  continue;
9726 
9727  /* ignore all time points after the effective horizon */
9728  if( timepoints[t] >= *hmax )
9729  break;
9730 
9731  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9732  * can split the cumulative constraint into two cumulative constraints
9733  */
9734  if( loads[t] <= capacity )
9735  {
9736  (*split) = timepoints[t];
9737  break;
9738  }
9739  }
9740  }
9741 
9742  /* free worst case profile */
9743  SCIPprofileFree(&profile);
9744 
9745  return SCIP_OKAY;
9746 }
9747 
9748 /** creates and adds a cumulative constraint */
9749 static
9751  SCIP* scip, /**< SCIP data structure */
9752  const char* name, /**< name of constraint */
9753  int nvars, /**< number of variables (jobs) */
9754  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9755  int* durations, /**< array containing corresponding durations */
9756  int* demands, /**< array containing corresponding demands */
9757  int capacity, /**< available cumulative capacity */
9758  int hmin, /**< left bound of time axis to be considered (including hmin) */
9759  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9760  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9761  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9762  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9763  * Usually set to TRUE. */
9764  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9765  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9766  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9767  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9768  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9769  * Usually set to TRUE. */
9770  SCIP_Bool local, /**< is constraint only valid locally?
9771  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9772  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9773  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9774  * adds coefficients to this constraint. */
9775  SCIP_Bool dynamic, /**< is constraint subject to aging?
9776  * Usually set to FALSE. Set to TRUE for own cuts which
9777  * are seperated as constraints. */
9778  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9779  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9780  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9781  * if it may be moved to a more global node?
9782  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9783  )
9784 {
9785  SCIP_CONS* cons;
9786 
9787  /* creates cumulative constraint and adds it to problem */
9788  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9789  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9790 
9791  /* adjust the effective time horizon of the new constraint */
9792  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9793  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9794 
9795  /* add and release new cumulative constraint */
9796  SCIP_CALL( SCIPaddCons(scip, cons) );
9797  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9798 
9799  return SCIP_OKAY;
9800 }
9801 
9802 /** computes the effective horizon and checks if the constraint can be decompsed */
9803 static
9805  SCIP* scip, /**< SCIP data structure */
9806  SCIP_CONS* cons, /**< cumulative constraint */
9807  int* ndelconss, /**< pointer to store the number of deleted constraints */
9808  int* naddconss, /**< pointer to store the number of added constraints */
9809  int* nchgsides /**< pointer to store the number of changed sides */
9810  )
9811 {
9812  SCIP_CONSDATA* consdata;
9813  int hmin;
9814  int hmax;
9815  int split;
9816 
9817  consdata = SCIPconsGetData(cons);
9818  assert(consdata != NULL);
9819 
9820  if( consdata->nvars <= 1 )
9821  return SCIP_OKAY;
9822 
9823  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9824  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9825 
9826  /* check if this time point improves the effective horizon */
9827  if( consdata->hmin < hmin )
9828  {
9829  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9830 
9831  consdata->hmin = hmin;
9832  (*nchgsides)++;
9833  }
9834 
9835  /* check if this time point improves the effective horizon */
9836  if( consdata->hmax > hmax )
9837  {
9838  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9839  consdata->hmax = hmax;
9840  (*nchgsides)++;
9841  }
9842 
9843  /* check if the constraint is redundant */
9844  if( consdata->hmax <= consdata->hmin )
9845  {
9846  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9847  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9848 
9849  SCIP_CALL( SCIPdelCons(scip, cons) );
9850  (*ndelconss)++;
9851  }
9852  else if( consdata->hmin < split && split < consdata->hmax )
9853  {
9854  char name[SCIP_MAXSTRLEN];
9855  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9856 
9857  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9858  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9859 
9860  assert(split < consdata->hmax);
9861 
9862  /* creates cumulative constraint and adds it to problem */
9863  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9864  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9867 
9868  /* adjust the effective time horizon of the constraint */
9869  consdata->hmax = split;
9870 
9871  assert(consdata->hmin < consdata->hmax);
9872 
9873  /* for the statistic we count the number of time we decompose a cumulative constraint */
9875  (*naddconss)++;
9876  }
9877 
9878  return SCIP_OKAY;
9879 }
9880 
9881 
9882 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9883  *
9884  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9885  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9886  *
9887  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9888  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9889  * down-lock of the corresponding start time variable can be removed.
9890  *
9891  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9892  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9893  * negative, than the job can be dual fixed to its earlier start time (est).
9894  *
9895  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9896  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9897  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9898  *
9899  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9900  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9901  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9902  * form variable domain is dual feasible.
9903  *
9904  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9905  * the cumulative condition; The deletion has to be done later.
9906  */
9907 static
9909  SCIP* scip, /**< SCIP data structure */
9910  int nvars, /**< number of start time variables (activities) */
9911  SCIP_VAR** vars, /**< array of start time variables */
9912  int* durations, /**< array of durations */
9913  int hmin, /**< left bound of time axis to be considered (including hmin) */
9914  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9915  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9916  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9917  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9918  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9919  int* nfixedvars, /**< pointer to store the number of fixed variables */
9920  int* nchgsides, /**< pointer to store the number of changed sides */
9921  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9922  )
9923 {
9924  SCIP_Real* downimpllbs;
9925  SCIP_Real* downimplubs;
9926  SCIP_Real* downproplbs;
9927  SCIP_Real* downpropubs;
9928  SCIP_Real* upimpllbs;
9929  SCIP_Real* upimplubs;
9930  SCIP_Real* upproplbs;
9931  SCIP_Real* uppropubs;
9932 
9933  int firstminect;
9934  int secondminect;
9935  int v;
9936 
9937  /* get temporary memory for storing probing results needed for step (4) and (5) */
9938  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9939  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9940  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9941  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9942  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9943  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9944  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9945  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9946 
9947  assert(scip != NULL);
9948  assert(nvars > 1);
9949  assert(cons != NULL);
9950 
9951  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9952 
9953  firstminect = INT_MAX;
9954  secondminect = INT_MAX;
9955 
9956  /* compute the two smallest earlier completion times; which are needed for step (5) */
9957  for( v = 0; v < nvars; ++v )
9958  {
9959  int ect;
9960 
9961  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9962 
9963  if( ect < firstminect )
9964  {
9965  secondminect = firstminect;
9966  firstminect = ect;
9967  }
9968  else if( ect < secondminect )
9969  secondminect = ect;
9970  }
9971 
9972  /* loop over all jobs and check if one of the 5 reductions can be applied */
9973  for( v = 0; v < nvars; ++v )
9974  {
9975  SCIP_VAR* var;
9976  int duration;
9977 
9978  int alternativelb;
9979  int minect;
9980  int est;
9981  int ect;
9982  int lst;
9983  int lct;
9984 
9985  var = vars[v];
9986  assert(var != NULL);
9987 
9988  duration = durations[v];
9989  assert(duration > 0);
9990 
9991  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9992  * time (lct)
9993  */
9994  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9995  ect = est + duration;
9996  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9997  lct = lst + duration;
9998 
9999  /* compute the earliest completion time of all remaining jobs */
10000  if( ect == firstminect )
10001  minect = secondminect;
10002  else
10003  minect = firstminect;
10004 
10005  /* compute potential alternative lower bound (step (4) and (5)) */
10006  alternativelb = MAX(hmin+1, minect);
10007  alternativelb = MIN(alternativelb, hmax);
10008 
10009  if( lct <= hmin )
10010  {
10011  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
10012  * cumulative condition
10013  */
10014  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10015  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10016 
10017  /* mark variable to be irrelevant */
10018  irrelevants[v] = TRUE;
10019 
10020  /* for the statistic we count the number of jobs which are irrelevant */
10021  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10022  }
10023  else if( lst <= hmin && SCIPconsIsChecked(cons) )
10024  {
10025  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
10026  * so the down lock can be omitted
10027  */
10028 
10029  assert(downlocks != NULL);
10030  assert(uplocks != NULL);
10031 
10032  if( !uplocks[v] )
10033  {
10034  /* the variables has no up lock and we can also remove the down lock;
10035  * => lst <= hmin and ect >= hmax
10036  * => remove job and reduce capacity by the demand of that job
10037  *
10038  * We mark the job to be deletable. The removement together with the capacity reducion is done later
10039  */
10040 
10041  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10042  SCIPvarGetName(var), ect - duration, lst, duration);
10043 
10044  /* mark variable to be irrelevant */
10045  irrelevants[v] = TRUE;
10046 
10047  /* for the statistic we count the number of jobs which always run during the effective horizon */
10049  }
10050 
10051  if( downlocks[v] )
10052  {
10053  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10054  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10055 
10056  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10057  downlocks[v] = FALSE;
10058  (*nchgsides)++;
10059 
10060  /* for the statistic we count the number of removed locks */
10062  }
10063  }
10064  else if( ect <= hmin )
10065  {
10066  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10067  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10068  * removed form the cumulative condition after it was fixed to its earliest start time
10069  */
10070 
10071  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10072  * bound;
10073  */
10074  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10075  {
10076  /* fix integer start time variable if possible to it lower bound */
10077  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10078  }
10079 
10080  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10081  {
10082  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10083  SCIPvarGetName(var), ect - duration, lst, duration);
10084 
10085  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10086  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10087 
10088  /* mark variable to be irrelevant */
10089  irrelevants[v] = TRUE;
10090 
10091  /* for the statistic we count the number of jobs which are dual fixed */
10093  }
10094  }
10095  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10096  {
10097  assert(downlocks != NULL);
10098 
10099  /* check step (4) and (5) */
10100 
10101  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10102  * is in favor of rounding the variable down
10103  */
10104  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10105  {
10106  SCIP_Bool roundable;
10107 
10108  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10109 
10110  if( roundable )
10111  {
10112  if( alternativelb > lst )
10113  {
10114  SCIP_Bool infeasible;
10115  SCIP_Bool fixed;
10116 
10117  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10118  assert(!infeasible);
10119  assert(fixed);
10120 
10121  (*nfixedvars)++;
10122 
10123  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10124  * constraints
10125  */
10127  }
10128  else
10129  {
10130  SCIP_Bool success;
10131 
10132  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10133  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10134  * infeasible we can apply the dual reduction; otherwise we do nothing
10135  */
10136  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10137  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10138  nfixedvars, &success, cutoff) );
10139 
10140  if( success )
10141  {
10143  }
10144  }
10145  }
10146  }
10147  }
10148 
10149  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10150  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10151  }
10152 
10153  /* free temporary memory */
10154  SCIPfreeBufferArray(scip, &uppropubs);
10155  SCIPfreeBufferArray(scip, &upproplbs);
10156  SCIPfreeBufferArray(scip, &upimplubs);
10157  SCIPfreeBufferArray(scip, &upimpllbs);
10158  SCIPfreeBufferArray(scip, &downpropubs);
10159  SCIPfreeBufferArray(scip, &downproplbs);
10160  SCIPfreeBufferArray(scip, &downimplubs);
10161  SCIPfreeBufferArray(scip, &downimpllbs);
10162 
10163  return SCIP_OKAY;
10164 }
10165 
10166 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10167  *
10168  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10169  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10170  *
10171  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10172  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10173  * up-lock of the corresponding start time variable can be removed.
10174  *
10175  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10176  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10177  * positive, than the job can be dual fixed to its latest start time (lst).
10178  *
10179  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10180  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10181  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10182  * of the corresponding job).
10183 
10184  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10185  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10186  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10187  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10188  *
10189  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10190  * the cumulative condition; The deletion has to be done later.
10191  */
10192 static
10194  SCIP* scip, /**< SCIP data structure */
10195  int nvars, /**< number of start time variables (activities) */
10196  SCIP_VAR** vars, /**< array of start time variables */
10197  int* durations, /**< array of durations */
10198  int hmin, /**< left bound of time axis to be considered (including hmin) */
10199  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10200  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10201  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10202  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10203  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10204  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10205  int* nchgsides, /**< pointer to store the number of changed sides */
10206  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10207  )
10208 {
10209  SCIP_Real* downimpllbs;
10210  SCIP_Real* downimplubs;
10211  SCIP_Real* downproplbs;
10212  SCIP_Real* downpropubs;
10213  SCIP_Real* upimpllbs;
10214  SCIP_Real* upimplubs;
10215  SCIP_Real* upproplbs;
10216  SCIP_Real* uppropubs;
10217 
10218  int firstmaxlst;
10219  int secondmaxlst;
10220  int v;
10221 
10222  /* get temporary memory for storing probing results needed for step (4) and (5) */
10223  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10224  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10225  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10226  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10227  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10228  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10229  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10230  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10231 
10232  assert(scip != NULL);
10233  assert(nvars > 1);
10234  assert(cons != NULL);
10235 
10236  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10237 
10238  firstmaxlst = INT_MIN;
10239  secondmaxlst = INT_MIN;
10240 
10241  /* compute the two largest latest start times; which are needed for step (5) */
10242  for( v = 0; v < nvars; ++v )
10243  {
10244  int lst;
10245 
10246  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10247 
10248  if( lst > firstmaxlst )
10249  {
10250  secondmaxlst = firstmaxlst;
10251  firstmaxlst = lst;
10252  }
10253  else if( lst > secondmaxlst )
10254  secondmaxlst = lst;
10255  }
10256 
10257  /* loop over all jobs and check if one of the 5 reductions can be applied */
10258  for( v = 0; v < nvars; ++v )
10259  {
10260  SCIP_VAR* var;
10261  int duration;
10262 
10263  int alternativeub;
10264  int maxlst;
10265  int est;
10266  int ect;
10267  int lst;
10268 
10269  var = vars[v];
10270  assert(var != NULL);
10271 
10272  duration = durations[v];
10273  assert(duration > 0);
10274 
10275  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10276  * time (lct)
10277  */
10278  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10279  ect = est + duration;
10280  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10281 
10282  /* compute the latest start time of all remaining jobs */
10283  if( lst == firstmaxlst )
10284  maxlst = secondmaxlst;
10285  else
10286  maxlst = firstmaxlst;
10287 
10288  /* compute potential alternative upper bound (step (4) and (5)) */
10289  alternativeub = MIN(hmax - 1, maxlst) - duration;
10290  alternativeub = MAX(alternativeub, hmin);
10291 
10292  if( est >= hmax )
10293  {
10294  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10295  * cumulative condition
10296  */
10297  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10298  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10299 
10300  /* mark variable to be irrelevant */
10301  irrelevants[v] = TRUE;
10302 
10303  /* for the statistic we count the number of jobs which are irrelevant */
10304  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10305  }
10306  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10307  {
10308  assert(downlocks != NULL);
10309  assert(uplocks != NULL);
10310 
10311  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10312  * so the up lock can be omitted
10313  */
10314 
10315  if( !downlocks[v] )
10316  {
10317  /* the variables has no down lock and we can also remove the up lock;
10318  * => lst <= hmin and ect >= hmax
10319  * => remove job and reduce capacity by the demand of that job
10320  */
10321  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10322  SCIPvarGetName(var), est, lst, duration);
10323 
10324  /* mark variable to be irrelevant */
10325  irrelevants[v] = TRUE;
10326 
10327  /* for the statistic we count the number of jobs which always run during the effective horizon */
10329  }
10330 
10331  if( uplocks[v] )
10332  {
10333  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10334  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10335 
10336  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10337  uplocks[v] = FALSE;
10338  (*nchgsides)++;
10339 
10340  /* for the statistic we count the number of removed locks */
10342  }
10343  }
10344  else if( lst >= hmax )
10345  {
10346  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10347  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10348  * removed form the cumulative condition after it was fixed to its latest start time
10349  */
10350 
10351  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10352  * bound
10353  */
10354  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10355  {
10356  /* fix integer start time variable if possible to its upper bound */
10357  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10358  }
10359 
10360  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10361  {
10362  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10363  SCIPvarGetName(var), est, lst, duration);
10364 
10365  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10366  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10367 
10368  /* mark variable to be irrelevant */
10369  irrelevants[v] = TRUE;
10370 
10371  /* for the statistic we count the number of jobs which are dual fixed */
10373  }
10374  }
10375  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10376  {
10377  assert(uplocks != NULL);
10378 
10379  /* check step (4) and (5) */
10380 
10381  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10382  * is in favor of rounding the variable down
10383  */
10384  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10385  {
10386  SCIP_Bool roundable;
10387 
10388  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10389 
10390  if( roundable )
10391  {
10392  if( alternativeub < est )
10393  {
10394  SCIP_Bool infeasible;
10395  SCIP_Bool fixed;
10396 
10397  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10398  assert(!infeasible);
10399  assert(fixed);
10400 
10401  (*nfixedvars)++;
10402 
10403  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10404  * constraints
10405  */
10407  }
10408  else
10409  {
10410  SCIP_Bool success;
10411 
10412  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10413  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10414  * in infeasible we can apply the dual reduction; otherwise we do nothing
10415  */
10416  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10417  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10418  nfixedvars, &success, cutoff) );
10419 
10420  if( success )
10421  {
10423  }
10424  }
10425  }
10426  }
10427  }
10428  }
10429 
10430  /* free temporary memory */
10431  SCIPfreeBufferArray(scip, &uppropubs);
10432  SCIPfreeBufferArray(scip, &upproplbs);
10433  SCIPfreeBufferArray(scip, &upimplubs);
10434  SCIPfreeBufferArray(scip, &upimpllbs);
10435  SCIPfreeBufferArray(scip, &downpropubs);
10436  SCIPfreeBufferArray(scip, &downproplbs);
10437  SCIPfreeBufferArray(scip, &downimplubs);
10438  SCIPfreeBufferArray(scip, &downimpllbs);
10439 
10440  return SCIP_OKAY;
10441 }
10442 
10443 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10444 static
10446  SCIP* scip, /**< SCIP data structure */
10447  SCIP_CONS* cons, /**< cumulative constraint */
10448  int* nfixedvars, /**< pointer to store the number of fixed variables */
10449  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10450  int* nchgsides, /**< pointer to store the number of changed sides */
10451  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10452  )
10453 {
10454  SCIP_CONSDATA* consdata;
10455  SCIP_Bool* irrelevants;
10456  int nvars;
10457  int v;
10458 
10459  assert(scip != NULL);
10460  assert(cons != NULL);
10461  assert(!(*cutoff));
10462 
10463  consdata = SCIPconsGetData(cons);
10464  assert(consdata != NULL);
10465 
10466  nvars = consdata->nvars;
10467 
10468  if( nvars <= 1 )
10469  return SCIP_OKAY;
10470 
10471  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10472  BMSclearMemoryArray(irrelevants, nvars);
10473 
10474  /* presolve constraint form the earlier start time point of view */
10475  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10476  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10477  irrelevants, nfixedvars, nchgsides, cutoff) );
10478 
10479  /* presolve constraint form the latest completion time point of view */
10480  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10481  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10482  irrelevants, nfixedvars, nchgsides, cutoff) );
10483 
10484  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10485  * order to ensure a correct behaviour
10486  */
10487  for( v = nvars-1; v >= 0; --v )
10488  {
10489  if( irrelevants[v] )
10490  {
10491  SCIP_VAR* var;
10492  int ect;
10493  int lst;
10494 
10495  var = consdata->vars[v];
10496  assert(var != NULL);
10497 
10498  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10499  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10500 
10501  /* check if the jobs runs completely during the effective horizon */
10502  if( lst <= consdata->hmin && ect >= consdata->hmax )
10503  {
10504  if( consdata->capacity < consdata->demands[v] )
10505  {
10506  *cutoff = TRUE;
10507  break;
10508  }
10509 
10510  consdata->capacity -= consdata->demands[v];
10511  consdata->varbounds = FALSE;
10512  }
10513 
10514  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10515  (*nchgcoefs)++;
10516  }
10517  }
10518 
10519  SCIPfreeBufferArray(scip, &irrelevants);
10520 
10521  return SCIP_OKAY;
10522 }
10523 
10524 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10525 static
10526 void collectDemands(
10527  SCIP* scip, /**< SCIP data structure */
10528  SCIP_CONSDATA* consdata, /**< constraint data */
10529  int* startindices, /**< permutation with rspect to the start times */
10530  int curtime, /**< current point in time */
10531  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10532  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10533  SCIP_Longint** demands, /**< pointer to array storing the demands */
10534  int* ndemands /**< pointer to store the number of different demands */
10535  )
10536 {
10537  int startindex;
10538  int ncountedvars;
10539 
10540  assert(demands != NULL);
10541  assert(ndemands != NULL);
10542 
10543  ncountedvars = 0;
10544  startindex = nstarted - 1;
10545 
10546  *ndemands = 0;
10547 
10548  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10549  while( nstarted - nfinished > ncountedvars )
10550  {
10551  SCIP_VAR* var;
10552  int endtime;
10553  int varidx;
10554 
10555  /* collect job information */
10556  varidx = startindices[startindex];
10557  assert(varidx >= 0 && varidx < consdata->nvars);
10558 
10559  var = consdata->vars[varidx];
10560  assert(var != NULL);
10561 
10562  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10563 
10564  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10565  if( endtime > curtime )
10566  {
10567  if( consdata->demands[varidx] < consdata->capacity )
10568  {
10569  (*demands)[*ndemands] = consdata->demands[varidx];
10570  (*ndemands)++;
10571  }
10572  ncountedvars++;
10573  }
10574 
10575  startindex--;
10576  }
10577 }
10578 
10579 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10580  * constraint
10581  */
10582 static
10584  SCIP* scip, /**< SCIP data structure */
10585  SCIP_CONS* cons, /**< constraint to be checked */
10586  int* startindices, /**< permutation with rspect to the start times */
10587  int curtime, /**< current point in time */
10588  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10589  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10590  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10591  )
10592 {
10593  SCIP_CONSDATA* consdata;
10594  SCIP_Longint* demands;
10595  SCIP_Real* profits;
10596  int* items;
10597  int ndemands;
10598  SCIP_Bool success;
10599  SCIP_Real solval;
10600  int j;
10601  assert(nstarted > nfinished);
10602 
10603  consdata = SCIPconsGetData(cons);
10604  assert(consdata != NULL);
10605  assert(consdata->nvars > 0);
10606  assert(consdata->capacity > 0);
10607 
10608  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10609  ndemands = 0;
10610 
10611  /* get demand array to initialize knapsack problem */
10612  collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10613 
10614  /* create array for profits */
10615  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10616  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10617  for( j = 0; j < ndemands; ++j )
10618  {
10619  profits[j] = (SCIP_Real) demands[j];
10620  items[j] = j;/* this is only a dummy value*/
10621  }
10622 
10623  /* solve knapsack problem and get maximum capacity usage <= capacity */
10624  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10625  items, NULL, NULL, NULL, NULL, &solval, &success) );
10626 
10627  assert(SCIPisFeasIntegral(scip, solval));
10628 
10629  /* store result */
10630  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10631 
10632  SCIPfreeBufferArray(scip, &items);
10633  SCIPfreeBufferArray(scip, &profits);
10634  SCIPfreeBufferArray(scip, &demands);
10635 
10636  return SCIP_OKAY;
10637 }
10638 
10639 /** try to tighten the capacity
10640  * -- using DP for knapsack, we find the maximum possible capacity usage
10641  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10642  */
10643 static
10645  SCIP* scip, /**< SCIP data structure */
10646  SCIP_CONS* cons, /**< cumulative constraint */
10647  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10648  int* nchgsides /**< pointer to store the number of changed sides */
10649  )
10650 {
10651  SCIP_CONSDATA* consdata;
10652  int* starttimes; /* stores when each job is starting */
10653  int* endtimes; /* stores when each job ends */
10654  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10655  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10656 
10657  int nvars; /* number of activities for this constraint */
10658  int freecapacity; /* remaining capacity */
10659  int curtime; /* point in time which we are just checking */
10660  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10661 
10662  int bestcapacity;
10663 
10664  int j;
10665 
10666  assert(scip != NULL);
10667  assert(cons != NULL);
10668  assert(nchgsides != NULL);
10669 
10670  consdata = SCIPconsGetData(cons);
10671  assert(consdata != NULL);
10672 
10673  nvars = consdata->nvars;
10674 
10675  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10676  if( nvars <= 1 || consdata->capacity <= 1 )
10677  return SCIP_OKAY;
10678 
10679  assert(consdata->vars != NULL);
10680 
10681  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10682  SCIPconsGetName(cons), consdata->capacity);
10683 
10684  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10685  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10686  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10687  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10688 
10689  /* create event point arrays */
10690  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10691  starttimes, endtimes, startindices, endindices, FALSE);
10692 
10693  bestcapacity = 1;
10694  endindex = 0;
10695  freecapacity = consdata->capacity;
10696 
10697  /* check each startpoint of a job whether the capacity is kept or not */
10698  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10699  {
10700  curtime = starttimes[j];
10701  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10702 
10703  /* remove the capacity requirments for all job which start at the curtime */
10704  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10705 
10706  /* add the capacity requirments for all job which end at the curtime */
10707  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10708 
10709  assert(freecapacity <= consdata->capacity);
10710  assert(endindex <= nvars);
10711 
10712  /* endindex - points to the next job which will finish */
10713  /* j - points to the last job that has been released */
10714 
10715  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10716  if( freecapacity < 0 )
10717  {
10718  int newcapacity;
10719 
10720  newcapacity = 1;
10721 
10722  /* get best possible upper bound on capacity usage */
10723  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10724 
10725  /* update bestcapacity */
10726  bestcapacity = MAX(bestcapacity, newcapacity);
10727  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10728  }
10729 
10730  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10731  if( freecapacity > 0 && freecapacity != consdata->capacity )
10732  {
10733  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10734  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10735  }
10736 
10737  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10738  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10739  {
10740  /* if demands[startindices[j]] == cap then exactly that job is running */
10741  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10742  bestcapacity = consdata->capacity;
10743  break;
10744  }
10745  } /*lint --e{850}*/
10746 
10747  /* free all buffer arrays */
10748  SCIPfreeBufferArray(scip, &endindices);
10749  SCIPfreeBufferArray(scip, &startindices);
10750  SCIPfreeBufferArray(scip, &endtimes);
10751  SCIPfreeBufferArray(scip, &starttimes);
10752 
10753  /* check whether capacity can be tightened and whether demands need to be adjusted */
10754  if( bestcapacity < consdata->capacity )
10755  {
10756  SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10757 
10758  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10759  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10760 
10761  for( j = 0; j < nvars; ++j )
10762  {
10763  if( consdata->demands[j] == consdata->capacity )
10764  {
10765  consdata->demands[j] = bestcapacity;
10766  (*nchgcoefs)++;
10767  }
10768  }
10769 
10770  consdata->capacity = bestcapacity;
10771  (*nchgsides)++;
10772 
10773  SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10774 
10775  consdata->varbounds = FALSE;
10776  }
10777 
10778  return SCIP_OKAY;
10779 }
10780 
10781 /** tries to change coefficients:
10782  * demand_j < cap && all other parallel jobs in conflict
10783  * ==> set demand_j := cap
10784  */
10785 static
10787  SCIP* scip, /**< SCIP data structure */
10788  SCIP_CONS* cons, /**< cumulative constraint */
10789  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10790  )
10791 {
10792  SCIP_CONSDATA* consdata;
10793  int nvars;
10794  int j;
10795  int oldnchgcoefs;
10796  int mindemand;
10797 
10798  assert(scip != NULL);
10799  assert(cons != NULL);
10800  assert(nchgcoefs != NULL);
10801 
10802  /* get constraint data for some parameter testings only! */
10803  consdata = SCIPconsGetData(cons);
10804  assert(consdata != NULL);
10805 
10806  nvars = consdata->nvars;
10807  oldnchgcoefs = *nchgcoefs;
10808 
10809  if( nvars <= 0 )
10810  return SCIP_OKAY;
10811 
10812  /* PRE1:
10813  * check all jobs j whether: r_j + r_min > capacity holds
10814  * if so: adjust r_j to capacity
10815  */
10816  mindemand = consdata->demands[0];
10817  for( j = 0; j < nvars; ++j )
10818  {
10819  mindemand = MIN(mindemand, consdata->demands[j]);
10820  }
10821 
10822  /*check each job */
10823  for( j = 0; j < nvars; ++j )
10824  {
10825  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10826  {
10827  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10828  consdata->demands[j], consdata->capacity);
10829  consdata->demands[j] = consdata->capacity;
10830  (*nchgcoefs)++;
10831  }
10832  }
10833 
10834  /* PRE2:
10835  * check for each job (with d_j < cap)
10836  * whether it is disjunctive to all others over the time horizon
10837  */
10838  for( j = 0; j < nvars; ++j )
10839  {
10840  SCIP_Bool chgcoef;
10841  int est_j;
10842  int lct_j;
10843  int i;
10844 
10845  assert(consdata->demands[j] <= consdata->capacity);
10846 
10847  if( consdata->demands[j] == consdata->capacity )
10848  continue;
10849 
10850  chgcoef = TRUE;
10851 
10852  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10853  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10854 
10855  for( i = 0; i < nvars; ++i )
10856  {
10857  int est_i;
10858  int lct_i;
10859 
10860  if( i == j )
10861  continue;
10862 
10863  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10864  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10865 
10866  if( est_i >= lct_j || est_j >= lct_i )
10867  continue;
10868 
10869  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10870  {
10871  chgcoef = FALSE;
10872  break;
10873  }
10874  }
10875 
10876  if( chgcoef )
10877  {
10878  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10879  consdata->demands[j], consdata->capacity);
10880  consdata->demands[j] = consdata->capacity;
10881  (*nchgcoefs)++;
10882  }
10883  }
10884 
10885  if( (*nchgcoefs) > oldnchgcoefs )
10886  {
10887  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10888  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10889  }
10890 
10891  return SCIP_OKAY;
10892 }
10893 
10894 #if 0
10895 /** try to reformulate constraint by replacing certain jobs */
10896 static
10897 SCIP_RETCODE reformulateCons(
10898  SCIP* scip, /**< SCIP data structure */
10899  SCIP_CONS* cons, /**< cumulative constraint */
10900  int* naggrvars /**< pointer to store the number of aggregated variables */
10901  )
10902 {
10903  SCIP_CONSDATA* consdata;
10904  int hmin;
10905  int hmax;
10906  int nvars;
10907  int v;
10908 
10909  consdata = SCIPconsGetData(cons);
10910  assert(cons != NULL);
10911 
10912  nvars = consdata->nvars;
10913  assert(nvars > 1);
10914 
10915  hmin = consdata->hmin;
10916  hmax = consdata->hmax;
10917  assert(hmin < hmax);
10918 
10919  for( v = 0; v < nvars; ++v )
10920  {
10921  SCIP_VAR* var;
10922  int duration;
10923  int est;
10924  int ect;
10925  int lst;
10926  int lct;
10927 
10928  var = consdata->vars[v];
10929  assert(var != NULL);
10930 
10931  duration = consdata->durations[v];
10932 
10933  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10934  ect = est + duration;
10935  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10936  lct = lst + duration;
10937 
10938  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10939  assert(lst > hmin || ect < hmax);
10940 
10941  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10942  {
10943  SCIP_VAR* aggrvar;
10944  char name[SCIP_MAXSTRLEN];
10945  SCIP_Bool infeasible;
10946  SCIP_Bool redundant;
10947  SCIP_Bool aggregated;
10948  int shift;
10949 
10950  shift = est - (hmin - lct + MIN(hmin, ect));
10951  assert(shift > 0);
10952  lst = hmin;
10953  duration = hmin - lct;
10954 
10955  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10956  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10957 
10958  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10959  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10961  SCIP_CALL( SCIPaddVar(scip, var) );
10962  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10963 
10964  assert(!infeasible);
10965  assert(!redundant);
10966  assert(aggregated);
10967 
10968  /* replace variable */
10969  consdata->durations[v] = duration;
10970  consdata->vars[v] = aggrvar;
10971 
10972  /* remove and add locks */
10973  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10974  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10975 
10976  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10977 
10978  (*naggrvars)++;
10979  }
10980  }
10981 
10982  return SCIP_OKAY;
10983 }
10984 #endif
10985 
10986 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10987 static
10989  SCIP* scip, /**< SCIP data structure */
10990  SCIP_CONS* cons, /**< cumulative constraint */
10991  int* naddconss /**< pointer to store the number of added constraints */
10992  )
10993 {
10994  SCIP_CONSDATA* consdata;
10995  SCIP_VAR** vars;
10996  int* durations;
10997  int* demands;
10998  int capacity;
10999  int halfcapacity;
11000  int mindemand;
11001  int nvars;
11002  int v;
11003 
11004  consdata = SCIPconsGetData(cons);
11005  assert(consdata != NULL);
11006 
11007  capacity = consdata->capacity;
11008 
11009  if( capacity == 1 )
11010  return SCIP_OKAY;
11011 
11012  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
11013  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
11014  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
11015 
11016  halfcapacity = capacity / 2;
11017  mindemand = consdata->capacity;
11018  nvars = 0;
11019 
11020  /* collect all jobs with demand larger than half of the capacity */
11021  for( v = 0; v < consdata->nvars; ++v )
11022  {
11023  if( consdata->demands[v] > halfcapacity )
11024  {
11025  vars[nvars] = consdata->vars[v];
11026  demands[nvars] = 1;
11027  durations[nvars] = consdata->durations[v];
11028  nvars++;
11029 
11030  mindemand = MIN(mindemand, consdata->demands[v]);
11031  }
11032  }
11033 
11034  if( nvars > 0 )
11035  {
11036  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11037  * job is still to large to be scheduled in parallel
11038  */
11039  for( v = 0; v < consdata->nvars; ++v )
11040  {
11041  if( consdata->demands[v] > halfcapacity )
11042  continue;
11043 
11044  if( mindemand + consdata->demands[v] > capacity )
11045  {
11046  demands[nvars] = 1;
11047  durations[nvars] = consdata->durations[v];
11048  vars[nvars] = consdata->vars[v];
11049  nvars++;
11050 
11051  /* @todo create one cumulative constraint and look for another small demand */
11052  break;
11053  }
11054  }
11055 
11056  /* creates cumulative constraint and adds it to problem */
11057  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11059  (*naddconss)++;
11060  }
11061 
11062  SCIPfreeBufferArray(scip, &demands);
11063  SCIPfreeBufferArray(scip, &durations);
11064  SCIPfreeBufferArray(scip, &vars);
11065 
11066  return SCIP_OKAY;
11067 }
11068 
11069 /** presolve given constraint */
11070 static
11072  SCIP* scip, /**< SCIP data structure */
11073  SCIP_CONS* cons, /**< cumulative constraint */
11074  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11075  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11076  int* nfixedvars, /**< pointer to store the number of fixed variables */
11077 #if 0
11078  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11079 #endif
11080  int* nchgbds, /**< pointer to store the number of changed bounds */
11081  int* ndelconss, /**< pointer to store the number of deleted constraints */
11082  int* naddconss, /**< pointer to store the number of added constraints */
11083  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11084  int* nchgsides, /**< pointer to store the number of changed sides */
11085  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11086  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11087  )
11088 {
11089  assert(!SCIPconsIsDeleted(cons));
11090 
11091  /* only perform dual reductions on model constraints */
11092  if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11093  {
11094  /* computes the effective horizon and checks if the constraint can be decomposed */
11095  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11096 
11097  if( SCIPconsIsDeleted(cons) )
11098  return SCIP_OKAY;
11099 
11100  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11101  * fixings (dual reductions)
11102  */
11103  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11104  {
11105  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11106 
11107  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11108  return SCIP_OKAY;
11109  }
11110 
11111  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11112 
11113  if( *cutoff || SCIPconsIsDeleted(cons) )
11114  return SCIP_OKAY;
11115  }
11116 
11117  /* remove jobs which have a demand larger than the capacity */
11118  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11119  assert((*cutoff) || checkDemands(scip, cons));
11120 
11121  if( *cutoff )
11122  return SCIP_OKAY;
11123 
11124  if( conshdlrdata->normalize )
11125  {
11126  /* divide demands by their greatest common divisor */
11127  normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11128  }
11129 
11130  /* delete constraint with one job */
11131  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11132 
11133  if( *cutoff || SCIPconsIsDeleted(cons) )
11134  return SCIP_OKAY;
11135 
11136  if( conshdlrdata->coeftightening )
11137  {
11138  /* try to tighten the capacity */
11139  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11140 
11141  /* try to tighten the coefficients */
11142  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11143  }
11144 
11145  assert(checkDemands(scip, cons) || *cutoff);
11146 
11147 #if 0
11148  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11149 #endif
11150 
11151  return SCIP_OKAY;
11152 }
11153 
11154 /**@name TClique Graph callbacks
11155  *
11156  * @{
11157  */
11158 
11159 /** tclique graph data */
11160 struct TCLIQUE_Graph
11161 {
11162  SCIP_VAR** vars; /**< start time variables each of them is a node */
11163  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11164  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11165  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11166  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11167  int* ninarcs; /**< number if in arcs for the precedence graph */
11168  int* noutarcs; /**< number if out arcs for the precedence graph */
11169  int* durations; /**< for each node the duration of the corresponding job */
11170  int nnodes; /**< number of nodes */
11171  int size; /**< size of the array */
11172 };
11173 
11174 /** gets number of nodes in the graph */
11175 static
11176 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11178  assert(tcliquegraph != NULL);
11179 
11180  return tcliquegraph->nnodes;
11181 }
11182 
11183 /** gets weight of nodes in the graph */
11184 static
11185 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11187  assert(tcliquegraph != NULL);
11188 
11189  return tcliquegraph->weights;
11190 }
11191 
11192 /** returns, whether the edge (node1, node2) is in the graph */
11193 static
11194 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11196  assert(tcliquegraph != NULL);
11197  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11198  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11199 
11200  /* check if an arc exits in the precedence graph */
11201  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11202  return TRUE;
11203 
11204  /* check if an edge exits in the non-overlapping graph */
11205  if( tcliquegraph->demandmatrix[node1][node2] )
11206  return TRUE;
11207 
11208  return FALSE;
11209 }
11210 
11211 /** selects all nodes from a given set of nodes which are adjacent to a given node
11212  * and returns the number of selected nodes
11213  */
11214 static
11215 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11217  int nadjnodes;
11218  int i;
11219 
11220  assert(tcliquegraph != NULL);
11221  assert(0 <= node && node < tcliquegraph->nnodes);
11222  assert(nnodes == 0 || nodes != NULL);
11223  assert(adjnodes != NULL);
11224 
11225  nadjnodes = 0;
11226 
11227  for( i = 0; i < nnodes; i++ )
11228  {
11229  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11230  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11231  assert(i == 0 || nodes[i-1] < nodes[i]);
11232 
11233  /* check if an edge exists */
11234  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11235  {
11236  /* current node is adjacent to given node */
11237  adjnodes[nadjnodes] = nodes[i];
11238  nadjnodes++;
11239  }
11240  }
11241 
11242  return nadjnodes;
11243 }
11244 
11245 /** generates cuts using a clique found by algorithm for maximum weight clique
11246  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11247  */
11248 static
11249 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11250 { /*lint --e{715}*/
11251  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11252 }
11253 
11254 /** print the tclique graph */
11255 #if 0
11256 static
11257 void tcliquePrint(
11258  SCIP* scip, /**< SCIP data structure */
11259  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11260  )
11261 {
11262  int nnodes;
11263  int i;
11264  int j;
11265 
11266  nnodes = tcliquegraph->nnodes;
11267 
11268  for( i = 0; i < nnodes; ++i )
11269  {
11270  for( j = 0; j < nnodes; ++j )
11271  {
11272  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11273  }
11274  SCIPinfoMessage(scip, NULL, "\n");
11275  }
11276 }
11277 #endif
11278 
11279 /** @} */
11280 
11281 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11282  * job corresponding to variable bound variable (vlbvar)
11283  *
11284  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11285  */
11286 static
11288  SCIP* scip, /**< SCIP data structure */
11289  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11290  SCIP_Real vlbcoef, /**< variable bound coefficient */
11291  SCIP_Real vlbconst, /**< variable bound constant */
11292  int duration /**< duration of the variable bound variable */
11293  )
11294 {
11295  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11296  {
11297  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11298  {
11299  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11300  return TRUE;
11301  }
11302  }
11303  else
11304  {
11305  SCIP_Real bound;
11306 
11307  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11308 
11309  if( SCIPisLT(scip, vlbcoef, 1.0) )
11310  {
11311  SCIP_Real ub;
11312 
11313  ub = SCIPvarGetUbLocal(vlbvar);
11314 
11315  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11316  if( SCIPisLE(scip, ub, bound) )
11317  return TRUE;
11318  }
11319  else
11320  {
11321  SCIP_Real lb;
11322 
11323  assert(SCIPisGT(scip, vlbcoef, 1.0));
11324 
11325  lb = SCIPvarGetLbLocal(vlbvar);
11326 
11327  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11328  if( SCIPisGE(scip, lb, bound) )
11329  return TRUE;
11330  }
11331  }
11332 
11333  return FALSE;
11334 }
11335 
11336 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11337  * job corresponding to variable which is bounded (var)
11338  *
11339  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11340  */
11341 static
11343  SCIP* scip, /**< SCIP data structure */
11344  SCIP_VAR* var, /**< variable which is bound from above */
11345  SCIP_Real vubcoef, /**< variable bound coefficient */
11346  SCIP_Real vubconst, /**< variable bound constant */
11347  int duration /**< duration of the variable which is bounded from above */
11348  )
11349 {
11350  SCIP_Real vlbcoef;
11351  SCIP_Real vlbconst;
11352 
11353  /* convert the variable upper bound into an variable lower bound */
11354  vlbcoef = 1.0 / vubcoef;
11355  vlbconst = -vubconst / vubcoef;
11356 
11357  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11358 }
11359 
11360 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11361  * others an index larger than the number if active variables
11362  */
11363 static
11365  SCIP* scip, /**< SCIP data structure */
11366  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11367  SCIP_VAR* var, /**< variable for which we want the index */
11368  int* idx /**< pointer to store the index */
11369  )
11370 {
11371  (*idx) = SCIPvarGetProbindex(var);
11372 
11373  if( (*idx) == -1 )
11374  {
11375  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11376  {
11377  (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11378  }
11379  else
11380  {
11381  int pos;
11382  int v;
11383 
11384  /**@todo we might want to add the aggregation path to graph */
11385 
11386  /* check if we have to realloc memory */
11387  if( tcliquegraph->size == tcliquegraph->nnodes )
11388  {
11389  int size;
11390 
11391  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11392  tcliquegraph->size = size;
11393 
11394  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11395  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11396  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11397  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11398  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11399 
11400  for( v = 0; v < tcliquegraph->nnodes; ++v )
11401  {
11402  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11403  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11404  }
11405  }
11406  assert(tcliquegraph->nnodes < tcliquegraph->size);
11407 
11408  pos = tcliquegraph->nnodes;
11409  assert(pos >= 0);
11410 
11411  tcliquegraph->durations[pos] = 0;
11412  tcliquegraph->weights[pos] = 0;
11413  tcliquegraph->vars[pos] = var;
11414 
11415  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11416  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11417 
11418  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11419  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11420 
11421  SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11422 
11423  tcliquegraph->nnodes++;
11424 
11425  for( v = 0; v < tcliquegraph->nnodes; ++v )
11426  {
11427  tcliquegraph->precedencematrix[v][pos] = 0;
11428  tcliquegraph->demandmatrix[v][pos] = 0;
11429  }
11430 
11431  (*idx) = tcliquegraph->nnodes;
11432  }
11433  }
11434  else
11435  {
11436  assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11437  }
11438 
11439  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11440 
11441  return SCIP_OKAY;
11442 }
11443 
11444 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11445  *
11446  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11447  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11448  *
11449  * (i) b = 1 and c >= d
11450  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11451  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11452  *
11453  */
11454 static
11456  SCIP* scip, /**< SCIP data structure */
11457  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11458  )
11459 {
11460  SCIP_VAR** vars;
11461  int nvars;
11462  int v;
11463 
11464  vars = SCIPgetVars(scip);
11465  nvars = SCIPgetNVars(scip);
11466 
11467  /* try to project each arc of the variable bound graph to precedence condition */
11468  for( v = 0; v < nvars; ++v )
11469  {
11470  SCIP_VAR** vbdvars;
11471  SCIP_VAR* var;
11472  SCIP_Real* vbdcoefs;
11473  SCIP_Real* vbdconsts;
11474  int nvbdvars;
11475  int idx1;
11476  int b;
11477 
11478  var = vars[v];
11479  assert(var != NULL);
11480 
11481  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11482  assert(idx1 >= 0);
11483 
11484  if( tcliquegraph->durations[idx1] == 0 )
11485  continue;
11486 
11487  vbdvars = SCIPvarGetVlbVars(var);
11488  vbdcoefs = SCIPvarGetVlbCoefs(var);
11489  vbdconsts = SCIPvarGetVlbConstants(var);
11490  nvbdvars = SCIPvarGetNVlbs(var);
11491 
11492  for( b = 0; b < nvbdvars; ++b )
11493  {
11494  int idx2;
11495 
11496  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11497  assert(idx2 >= 0);
11498 
11499  if( tcliquegraph->durations[idx2] == 0 )
11500  continue;
11501 
11502  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11503  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11504  }
11505 
11506  vbdvars = SCIPvarGetVubVars(var);
11507  vbdcoefs = SCIPvarGetVubCoefs(var);
11508  vbdconsts = SCIPvarGetVubConstants(var);
11509  nvbdvars = SCIPvarGetNVubs(var);
11510 
11511  for( b = 0; b < nvbdvars; ++b )
11512  {
11513  int idx2;
11514 
11515  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11516  assert(idx2 >= 0);
11517 
11518  if( tcliquegraph->durations[idx2] == 0 )
11519  continue;
11520 
11521  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11522  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11523  }
11524 
11525  for( b = v+1; b < nvars; ++b )
11526  {
11527  int idx2;
11528 
11529  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11530  assert(idx2 >= 0);
11531 
11532  if( tcliquegraph->durations[idx2] == 0 )
11533  continue;
11534 
11535  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11536  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11537  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11538 
11539  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11540  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11541  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11542  }
11543  }
11544 
11545  return SCIP_OKAY;
11546 }
11547 
11548 /** compute the transitive closer of the given graph and the number of in and out arcs */
11549 static
11550 void transitiveClosure(
11551  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11552  int* ninarcs, /**< array to store the number of in arcs */
11553  int* noutarcs, /**< array to store the number of out arcs */
11554  int nnodes /**< number if nodes */
11555  )
11556 {
11557  int i;
11558  int j;
11559  int k;
11560 
11561  for( i = 0; i < nnodes; ++i )
11562  {
11563  for( j = 0; j < nnodes; ++j )
11564  {
11565  if( adjmatrix[i][j] )
11566  {
11567  ninarcs[j]++;
11568  noutarcs[i]++;
11569 
11570  for( k = 0; k < nnodes; ++k )
11571  {
11572  if( adjmatrix[j][k] )
11573  adjmatrix[i][k] = TRUE;
11574  }
11575  }
11576  }
11577  }
11578 }
11579 
11580 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11581 static
11583  SCIP* scip, /**< SCIP data structure */
11584  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11585  SCIP_CONS** conss, /**< array of cumulative constraints */
11586  int nconss /**< number of cumulative constraints */
11587  )
11588 {
11589  int c;
11590 
11591  /* use the cumulative constraints to initialize the none overlapping graph */
11592  for( c = 0; c < nconss; ++c )
11593  {
11594  SCIP_CONSDATA* consdata;
11595  SCIP_VAR** vars;
11596  int* demands;
11597  int capacity;
11598  int nvars;
11599  int i;
11600 
11601  consdata = SCIPconsGetData(conss[c]);
11602  assert(consdata != NULL);
11603 
11604  vars = consdata->vars;
11605  demands = consdata->demands;
11606 
11607  nvars = consdata->nvars;
11608  capacity = consdata->capacity;
11609 
11610  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11611 
11612  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11613  for( i = 0; i < nvars; ++i )
11614  {
11615  int idx1;
11616  int j;
11617 
11618  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11619  assert(idx1 >= 0);
11620 
11621  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11622  continue;
11623 
11624  for( j = i+1; j < nvars; ++j )
11625  {
11626  assert(consdata->durations[j] > 0);
11627 
11628  if( demands[i] + demands[j] > capacity )
11629  {
11630  int idx2;
11631  int est1;
11632  int est2;
11633  int lct1;
11634  int lct2;
11635 
11636  /* check if the effective horizon is large enough */
11637  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11638  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11639 
11640  /* at least one of the jobs needs to start at hmin or later */
11641  if( est1 < consdata->hmin && est2 < consdata->hmin )
11642  continue;
11643 
11644  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11645  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11646 
11647  /* at least one of the jobs needs to finish not later then hmin */
11648  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11649  continue;
11650 
11651  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11652  assert(idx2 >= 0);
11653  assert(idx1 != idx2);
11654 
11655  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11656  continue;
11657 
11658  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11659 
11660  assert(tcliquegraph->durations[idx1] > 0);
11661  assert(tcliquegraph->durations[idx2] > 0);
11662 
11663  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11664  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11665  }
11666  }
11667  }
11668  }
11669 
11670  return SCIP_OKAY;
11671 }
11672 
11673 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11674  * of jobs cannot run in parallel
11675  */
11676 static
11678  SCIP* scip, /**< SCIP data structure */
11679  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11680  SCIP_CONS** conss, /**< array of cumulative constraints */
11681  int nconss /**< number of cumulative constraints */
11682  )
11683 {
11684  assert(scip != NULL);
11685  assert(tcliquegraph != NULL);
11686 
11687  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11688  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11689 
11690  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11691  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11692 
11693  /* constraints non-overlapping graph */
11694  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11695 
11696  return SCIP_OKAY;
11697 }
11698 
11699 /** create cumulative constraint from conflict set */
11700 static
11702  SCIP* scip, /**< SCIP data structure */
11703  const char* name, /**< constraint name */
11704  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11705  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11706  int ncliquenodes /**< number of nodes in the clique */
11707  )
11708 {
11709  SCIP_CONS* cons;
11710  SCIP_VAR** vars;
11711  int* durations;
11712  int* demands;
11713  int v;
11714 
11715  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11716  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11717  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11718 
11719  SCIPsortInt(cliquenodes, ncliquenodes);
11720 
11721  /* collect variables, durations, and demands */
11722  for( v = 0; v < ncliquenodes; ++v )
11723  {
11724  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11725  assert(durations[v] > 0);
11726  demands[v] = 1;
11727  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11728  }
11729 
11730  /* create (unary) cumulative constraint */
11731  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11733 
11734  SCIP_CALL( SCIPaddCons(scip, cons) );
11735  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11736 
11737  /* free buffers */
11738  SCIPfreeBufferArray(scip, &demands);
11739  SCIPfreeBufferArray(scip, &durations);
11740  SCIPfreeBufferArray(scip, &vars);
11741 
11742  return SCIP_OKAY;
11743 }
11744 
11745 /** search for cumulative constrainst */
11746 static
11748  SCIP* scip, /**< SCIP data structure */
11749  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11750  int* naddconss /**< pointer to store the number of added constraints */
11751  )
11752 {
11753  TCLIQUE_STATUS tcliquestatus;
11754  SCIP_Bool* precedencerow;
11755  SCIP_Bool* precedencecol;
11756  SCIP_Bool* demandrow;
11757  SCIP_Bool* demandcol;
11758  SCIP_HASHTABLE* covered;
11759  int* cliquenodes;
11760  int ncliquenodes;
11761  int cliqueweight;
11762  int ntreenodes;
11763  int nnodes;
11764  int nconss;
11765  int v;
11766 
11767  nnodes = tcliquegraph->nnodes;
11768  nconss = 0;
11769 
11770  /* initialize the weight of each job with its duration */
11771  for( v = 0; v < nnodes; ++v )
11772  {
11773  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11774  }
11775 
11776  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11777  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11778  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11779  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11780  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11781 
11782  /* create a hash table to store all start time variables which are already covered by at least one clique */
11783  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11784  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11785 
11786  /* for each variables/job we are ... */
11787  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11788  {
11789  char name[SCIP_MAXSTRLEN];
11790  int c;
11791 
11792  /* jobs with zero durations are skipped */
11793  if( tcliquegraph->durations[v] == 0 )
11794  continue;
11795 
11796  /* check if the start time variable is already covered by at least one clique */
11797  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11798  continue;
11799 
11800  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11801 
11802  /* temporarily remove the connection via the precedence graph */
11803  for( c = 0; c < nnodes; ++c )
11804  {
11805  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11806  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11807 
11808  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11809  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11810 
11811 #if 0
11812  if( precedencerow[c] || precedencecol[c] )
11813  {
11814  tcliquegraph->demandmatrix[v][c] = FALSE;
11815  tcliquegraph->demandmatrix[c][v] = FALSE;
11816  }
11817 #endif
11818 
11819  tcliquegraph->precedencematrix[c][v] = FALSE;
11820  tcliquegraph->precedencematrix[v][c] = FALSE;
11821  }
11822 
11823  /* find (heuristically) maximum cliques which includes node v */
11824  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11825  tcliquegraph, tcliqueNewsolClique, NULL,
11826  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11827  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11828 
11829  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11830 
11831  if( ncliquenodes == 1 )
11832  continue;
11833 
11834  /* construct constraint name */
11835  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11836 
11837  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11838  nconss++;
11839 
11840  /* all start time variable to covered hash table */
11841  for( c = 0; c < ncliquenodes; ++c )
11842  {
11843  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11844  }
11845 
11846  /* copy the precedence relations back */
11847  for( c = 0; c < nnodes; ++c )
11848  {
11849  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11850  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11851 
11852  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11853  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11854  }
11855  }
11856 
11857  SCIPhashtableFree(&covered);
11858 
11859  SCIPfreeBufferArray(scip, &demandcol);
11860  SCIPfreeBufferArray(scip, &demandrow);
11861  SCIPfreeBufferArray(scip, &precedencecol);
11862  SCIPfreeBufferArray(scip, &precedencerow);
11863  SCIPfreeBufferArray(scip, &cliquenodes);
11864 
11865  (*naddconss) += nconss;
11866 
11867  /* for the statistic we count the number added disjunctive constraints */
11868  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11869 
11870  return SCIP_OKAY;
11871 }
11872 
11873 /** create precedence constraint (as variable bound constraint */
11874 static
11876  SCIP* scip, /**< SCIP data structure */
11877  const char* name, /**< constraint name */
11878  SCIP_VAR* var, /**< variable x that has variable bound */
11879  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11880  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11881  )
11882 {
11883  SCIP_CONS* cons;
11884 
11885  /* create variable bound constraint */
11886  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11888 
11889  SCIPdebugPrintCons(scip, cons, NULL);
11890 
11891  /* add constraint to problem and release it */
11892  SCIP_CALL( SCIPaddCons(scip, cons) );
11893  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11894 
11895  return SCIP_OKAY;
11896 }
11897 
11898 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11899 static
11901  SCIP* scip, /**< SCIP data structure */
11902  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11903  int source, /**< index of the source node */
11904  int sink, /**< index of the sink node */
11905  int* naddconss /**< pointer to store the number of added constraints */
11906  )
11907 {
11908  TCLIQUE_WEIGHT cliqueweight;
11909  TCLIQUE_STATUS tcliquestatus;
11910  SCIP_VAR** vars;
11911  int* cliquenodes;
11912  int nnodes;
11913  int lct;
11914  int est;
11915  int i;
11916 
11917  int ntreenodes;
11918  int ncliquenodes;
11919 
11920  /* check if source and sink are connencted */
11921  if( !tcliquegraph->precedencematrix[source][sink] )
11922  return SCIP_OKAY;
11923 
11924  nnodes = tcliquegraph->nnodes;
11925  vars = tcliquegraph->vars;
11926 
11927  /* reset the weights to zero */
11928  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11929 
11930  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11931  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11932  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11933 
11934  /* weight all jobs which run for sure between source and sink with their duration */
11935  for( i = 0; i < nnodes; ++i )
11936  {
11937  SCIP_VAR* var;
11938  int duration;
11939 
11940  var = vars[i];
11941  assert(var != NULL);
11942 
11943  duration = tcliquegraph->durations[i];
11944 
11945  if( i == source || i == sink )
11946  {
11947  /* source and sink are not weighted */
11948  tcliquegraph->weights[i] = 0;
11949  }
11950  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11951  {
11952  /* job i runs after source and before sink */
11953  tcliquegraph->weights[i] = duration;
11954  }
11955  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11956  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11957  {
11958  /* job i run in between due the bounds of the start time variables */
11959  tcliquegraph->weights[i] = duration;
11960  }
11961  else
11962  tcliquegraph->weights[i] = 0;
11963  }
11964 
11965  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11966 
11967  /* find (heuristically) maximum cliques */
11968  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11969  tcliquegraph, tcliqueNewsolClique, NULL,
11970  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11971  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11972 
11973  if( ncliquenodes > 1 )
11974  {
11975  char name[SCIP_MAXSTRLEN];
11976  int distance;
11977 
11978  /* construct constraint name */
11979  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11980 
11981  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11982  * duration of the source job
11983  */
11984  distance = cliqueweight + tcliquegraph->durations[source];
11985 
11986  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11987  (*naddconss)++;
11988  }
11989 
11990  SCIPfreeBufferArray(scip, &cliquenodes);
11991 
11992  return SCIP_OKAY;
11993 }
11994 
11995 /** search for precedence constraints
11996  *
11997  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11998  * corresponding two jobs
11999  */
12000 static
12002  SCIP* scip, /**< SCIP data structure */
12003  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
12004  int* naddconss /**< pointer to store the number of added constraints */
12005  )
12006 {
12007  int* sources;
12008  int* sinks;
12009  int nconss;
12010  int nnodes;
12011  int nsources;
12012  int nsinks;
12013  int i;
12014 
12015  nnodes = tcliquegraph->nnodes;
12016  nconss = 0;
12017 
12018  nsources = 0;
12019  nsinks = 0;
12020 
12021  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
12022  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
12023 
12024  /* first collect all sources and sinks */
12025  for( i = 0; i < nnodes; ++i )
12026  {
12027  if( tcliquegraph->ninarcs[i] == 0 )
12028  {
12029  sources[nsources] = i;
12030  nsources++;
12031  }
12032 
12033  if( tcliquegraph->ninarcs[i] == 0 )
12034  {
12035  sinks[nsinks] = i;
12036  nsinks++;
12037  }
12038  }
12039 
12040  /* compute for each node a minimum distance to each sources and each sink */
12041  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12042  {
12043  int j;
12044 
12045  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12046  {
12047  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12048  }
12049 
12050  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12051  {
12052  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12053  }
12054  }
12055 
12056  (*naddconss) += nconss;
12057 
12058  /* for the statistic we count the number added variable constraints */
12059  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12060 
12061  SCIPfreeBufferArray(scip, &sinks);
12062  SCIPfreeBufferArray(scip, &sources);
12063 
12064  return SCIP_OKAY;
12065 }
12066 
12067 /** initialize the assumed durations for each variable */
12068 static
12070  SCIP* scip, /**< SCIP data structure */
12071  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12072  SCIP_CONS** conss, /**< cumulative constraints */
12073  int nconss /**< number of cumulative constraints */
12074  )
12075 {
12076  int c;
12077 
12078  /* use the cumulative structure to define the duration we are using for each job */
12079  for( c = 0; c < nconss; ++c )
12080  {
12081  SCIP_CONSDATA* consdata;
12082  SCIP_VAR** vars;
12083  int nvars;
12084  int v;
12085 
12086  consdata = SCIPconsGetData(conss[c]);
12087  assert(consdata != NULL);
12088 
12089  vars = consdata->vars;
12090  nvars = consdata->nvars;
12091 
12092  for( v = 0; v < nvars; ++v )
12093  {
12094  int idx;
12095 
12096  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12097  assert(idx >= 0);
12098 
12099  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12100  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12101  * general this is not the case. Therefore, the question would be which duration should be used?
12102  */
12103  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12104  assert(tcliquegraph->durations[idx] > 0);
12105  }
12106  }
12107 
12108  return SCIP_OKAY;
12109 }
12110 
12111 /** create tclique graph */
12112 static
12114  SCIP* scip, /**< SCIP data structure */
12115  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12116  )
12117 {
12118  SCIP_VAR** vars;
12119  SCIP_HASHMAP* varmap;
12120  SCIP_Bool** precedencematrix;
12121  SCIP_Bool** demandmatrix;
12122  int* ninarcs;
12123  int* noutarcs;
12124  int* durations;
12125  int* weights;
12126  int nvars;
12127  int v;
12128 
12129  vars = SCIPgetVars(scip);
12130  nvars = SCIPgetNVars(scip);
12131 
12132  /* allocate memory for the tclique graph data structure */
12133  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12134 
12135  /* create the variable mapping hash map */
12136  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12137 
12138  /* each active variables get a node in the graph */
12139  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12140 
12141  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12142  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12143  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12144 
12145  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12146  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12147  BMSclearMemoryArray(weights, nvars);
12148 
12149  /* array to store the number of in arc of the precedence graph */
12150  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12151  BMSclearMemoryArray(ninarcs, nvars);
12152 
12153  /* array to store the number of out arc of the precedence graph */
12154  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12155  BMSclearMemoryArray(noutarcs, nvars);
12156 
12157  /* array to store the used duration for each node */
12158  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12159  BMSclearMemoryArray(durations, nvars);
12160 
12161  for( v = 0; v < nvars; ++v )
12162  {
12163  SCIP_VAR* var;
12164 
12165  var = vars[v];
12166  assert(var != NULL);
12167 
12168  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12169  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12170 
12171  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12172  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12173 
12174  /* insert all active variables into the garph */
12175  assert(SCIPvarGetProbindex(var) == v);
12176  SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12177  }
12178 
12179  (*tcliquegraph)->nnodes = nvars;
12180  (*tcliquegraph)->varmap = varmap;
12181  (*tcliquegraph)->precedencematrix = precedencematrix;
12182  (*tcliquegraph)->demandmatrix = demandmatrix;
12183  (*tcliquegraph)->weights = weights;
12184  (*tcliquegraph)->ninarcs = ninarcs;
12185  (*tcliquegraph)->noutarcs = noutarcs;
12186  (*tcliquegraph)->durations = durations;
12187  (*tcliquegraph)->size = nvars;
12188 
12189  return SCIP_OKAY;
12190 }
12191 
12192 /** frees the tclique graph */
12193 static
12194 void freeTcliqueGraph(
12195  SCIP* scip, /**< SCIP data structure */
12196  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12197  )
12198 {
12199  int v;
12200 
12201  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12202  {
12203  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12204  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12205  }
12206 
12207  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12208  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12209  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12210  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12211  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12212  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12213  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12214  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12215 
12216  SCIPfreeBuffer(scip, tcliquegraph);
12217 }
12218 
12219 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12220  * constrains (disjunctive constraint)
12221  */
12222 static
12224  SCIP* scip, /**< SCIP data structure */
12225  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12226  SCIP_CONS** conss, /**< array of cumulative constraints */
12227  int nconss, /**< number of cumulative constraints */
12228  int* naddconss /**< pointer to store the number of added constraints */
12229  )
12230 {
12231  TCLIQUE_GRAPH* tcliquegraph;
12232 
12233  /* create tclique graph */
12234  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12235 
12236  /* define for each job a duration */
12237  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12238 
12239  /* constuct incompatibility graph */
12240  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12241 
12242  /* search for new precedence constraints */
12243  if( conshdlrdata->detectvarbounds )
12244  {
12245  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12246  }
12247 
12248  /* search for new cumulative constraints */
12249  if( conshdlrdata->detectdisjunctive )
12250  {
12251  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12252  }
12253 
12254  /* free tclique graph data structure */
12255  freeTcliqueGraph(scip, &tcliquegraph);
12256 
12257  return SCIP_OKAY;
12258 }
12259 
12260 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12261 static
12263  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12264  )
12265 {
12266  SCIP_VAR** vars;
12267  int nvars;
12268  int v;
12269 
12270  if( consdata->validsignature )
12271  return;
12272 
12273  vars = consdata->vars;
12274  nvars = consdata->nvars;
12275 
12276  for( v = 0; v < nvars; ++v )
12277  {
12278  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12279  }
12280 
12281  consdata->validsignature = TRUE;
12282 }
12283 
12284 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12285 static
12286 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12287 { /*lint --e{715}*/
12288  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12289 
12290  assert(consdata != NULL);
12291  assert(0 <= ind1 && ind1 < consdata->nvars);
12292  assert(0 <= ind2 && ind2 < consdata->nvars);
12293 
12294  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12295 }
12296 
12297 /** run a pairwise comparison */
12298 static
12300  SCIP* scip, /**< SCIP data structure */
12301  SCIP_CONS** conss, /**< array of cumulative constraints */
12302  int nconss, /**< number of cumulative constraints */
12303  int* ndelconss /**< pointer to store the number of deletedconstraints */
12304  )
12305 {
12306  int i;
12307  int j;
12308 
12309  for( i = 0; i < nconss; ++i )
12310  {
12311  SCIP_CONSDATA* consdata0;
12312  SCIP_CONS* cons0;
12313 
12314  cons0 = conss[i];
12315  assert(cons0 != NULL);
12316 
12317  consdata0 = SCIPconsGetData(cons0);
12318  assert(consdata0 != NULL);
12319 
12320  consdataCalcSignature(consdata0);
12321  assert(consdata0->validsignature);
12322 
12323  for( j = i+1; j < nconss; ++j )
12324  {
12325  SCIP_CONSDATA* consdata1;
12326  SCIP_CONS* cons1;
12327 
12328  cons1 = conss[j];
12329  assert(cons1 != NULL);
12330 
12331  consdata1 = SCIPconsGetData(cons1);
12332  assert(consdata1 != NULL);
12333 
12334  if( consdata0->capacity != consdata1->capacity )
12335  continue;
12336 
12337  consdataCalcSignature(consdata1);
12338  assert(consdata1->validsignature);
12339 
12340  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12341  {
12342  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12343  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12344  assert((consdata0->signature & (~consdata1->signature)) == 0);
12345  }
12346 
12347  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12348  {
12349  int* perm0;
12350  int* perm1;
12351  int v0;
12352  int v1;
12353 
12354  if( consdata0->nvars > consdata1->nvars )
12355  continue;
12356 
12357  if( consdata0->hmin < consdata1->hmin )
12358  continue;
12359 
12360  if( consdata0->hmax > consdata1->hmax )
12361  continue;
12362 
12363  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12364  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12365 
12366  /* call sorting method */
12367  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12368  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12369 
12370  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12371  {
12372  SCIP_VAR* var0;
12373  SCIP_VAR* var1;
12374  int idx0;
12375  int idx1;
12376  int comp;
12377 
12378  idx0 = perm0[v0];
12379  idx1 = perm1[v1];
12380 
12381  var0 = consdata0->vars[idx0];
12382 
12383  var1 = consdata1->vars[idx1];
12384 
12385  comp = SCIPvarCompare(var0, var1);
12386 
12387  if( comp == 0 )
12388  {
12389  int duration0;
12390  int duration1;
12391  int demand0;
12392  int demand1;
12393 
12394  demand0 = consdata0->demands[idx0];
12395  duration0 = consdata0->durations[idx0];
12396 
12397  demand1 = consdata1->demands[idx1];
12398  duration1 = consdata1->durations[idx1];
12399 
12400  if( demand0 != demand1 )
12401  break;
12402 
12403  if( duration0 != duration1 )
12404  break;
12405 
12406  v0++;
12407  v1++;
12408  }
12409  else if( comp > 0 )
12410  v1++;
12411  else
12412  break;
12413  }
12414 
12415  if( v0 == consdata0->nvars )
12416  {
12417  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12418  {
12419  initializeLocks(consdata1, TRUE);
12420  }
12421 
12422  /* coverity[swapped_arguments] */
12423  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12424 
12425  SCIP_CALL( SCIPdelCons(scip, cons0) );
12426  (*ndelconss)++;
12427  }
12428 
12429  SCIPfreeBufferArray(scip, &perm1);
12430  SCIPfreeBufferArray(scip, &perm0);
12431  }
12432  }
12433  }
12434 
12435  return SCIP_OKAY;
12436 }
12437 
12438 /** strengthen the variable bounds using the cumulative condition */
12439 static
12441  SCIP* scip, /**< SCIP data structure */
12442  SCIP_CONS* cons, /**< constraint to propagate */
12443  int* nchgbds, /**< pointer to store the number of changed bounds */
12444  int* naddconss /**< pointer to store the number of added constraints */
12445  )
12446 {
12447  SCIP_CONSDATA* consdata;
12448  SCIP_VAR** vars;
12449  int* durations;
12450  int* demands;
12451  int capacity;
12452  int nvars;
12453  int nconss;
12454  int i;
12455 
12456  consdata = SCIPconsGetData(cons);
12457  assert(consdata != NULL);
12458 
12459  /* check if the variable bounds got already strengthen by the cumulative constraint */
12460  if( consdata->varbounds )
12461  return SCIP_OKAY;
12462 
12463  vars = consdata->vars;
12464  durations = consdata->durations;
12465  demands = consdata->demands;
12466  capacity = consdata->capacity;
12467  nvars = consdata->nvars;
12468 
12469  nconss = 0;
12470 
12471  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12472  {
12473  SCIP_VAR** vbdvars;
12474  SCIP_VAR* var;
12475  SCIP_Real* vbdcoefs;
12476  SCIP_Real* vbdconsts;
12477  int nvbdvars;
12478  int b;
12479  int j;
12480 
12481  var = consdata->vars[i];
12482  assert(var != NULL);
12483 
12484  vbdvars = SCIPvarGetVlbVars(var);
12485  vbdcoefs = SCIPvarGetVlbCoefs(var);
12486  vbdconsts = SCIPvarGetVlbConstants(var);
12487  nvbdvars = SCIPvarGetNVlbs(var);
12488 
12489  for( b = 0; b < nvbdvars; ++b )
12490  {
12491  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12492  {
12493  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12494  {
12495  for( j = 0; j < nvars; ++j )
12496  {
12497  if( vars[j] == vbdvars[b] )
12498  break;
12499  }
12500  if( j == nvars )
12501  continue;
12502 
12503  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12504  {
12505  SCIP_Bool infeasible;
12506  char name[SCIP_MAXSTRLEN];
12507  int nlocalbdchgs;
12508 
12509  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12510 
12511  /* construct constraint name */
12512  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12513 
12514  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12515  nconss++;
12516 
12517  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12518  assert(!infeasible);
12519 
12520  (*nchgbds) += nlocalbdchgs;
12521  }
12522  }
12523  }
12524  }
12525  }
12526 
12527  (*naddconss) += nconss;
12528 
12529  consdata->varbounds = TRUE;
12530 
12531  return SCIP_OKAY;
12532 }
12533 
12534 /** helper function to enforce constraints */
12535 static
12537  SCIP* scip, /**< SCIP data structure */
12538  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12539  SCIP_CONS** conss, /**< constraints to process */
12540  int nconss, /**< number of constraints */
12541  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12542  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12543  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12544  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12545  )
12546 {
12547  SCIP_CONSHDLRDATA* conshdlrdata;
12548 
12549  assert(conshdlr != NULL);
12550  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12551  assert(nconss == 0 || conss != NULL);
12552  assert(result != NULL);
12553 
12554  if( solinfeasible )
12555  {
12556  *result = SCIP_INFEASIBLE;
12557  return SCIP_OKAY;
12558  }
12559 
12560  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12561  sol == NULL ? "LP" : "relaxation");
12562 
12563  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12564  assert(conshdlrdata != NULL);
12565 
12566  (*result) = SCIP_FEASIBLE;
12567 
12568  if( conshdlrdata->usebinvars )
12569  {
12570  SCIP_Bool separated;
12571  SCIP_Bool cutoff;
12572  int c;
12573 
12574  separated = FALSE;
12575 
12576  /* first check if a constraints is violated */
12577  for( c = 0; c < nusefulconss; ++c )
12578  {
12579  SCIP_CONS* cons;
12580  SCIP_Bool violated;
12581 
12582  cons = conss[c];
12583  assert(cons != NULL);
12584 
12585  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12586 
12587  if( !violated )
12588  continue;
12589 
12590  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12591  if ( cutoff )
12592  {
12593  *result = SCIP_CUTOFF;
12594  return SCIP_OKAY;
12595  }
12596  }
12597 
12598  for( ; c < nconss && !separated; ++c )
12599  {
12600  SCIP_CONS* cons;
12601  SCIP_Bool violated;
12602 
12603  cons = conss[c];
12604  assert(cons != NULL);
12605 
12606  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12607 
12608  if( !violated )
12609  continue;
12610 
12611  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12612  if ( cutoff )
12613  {
12614  *result = SCIP_CUTOFF;
12615  return SCIP_OKAY;
12616  }
12617  }
12618 
12619  if( separated )
12620  (*result) = SCIP_SEPARATED;
12621  }
12622  else
12623  {
12624  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12625  }
12626 
12627  return SCIP_OKAY;
12628 }
12629 
12630 /**@} */
12631 
12632 
12633 /**@name Callback methods of constraint handler
12634  *
12635  * @{
12636  */
12637 
12638 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12639 static
12640 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12641 { /*lint --e{715}*/
12642  assert(scip != NULL);
12643  assert(conshdlr != NULL);
12644  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12645 
12646  /* call inclusion method of constraint handler */
12648 
12650 
12651  *valid = TRUE;
12652 
12653  return SCIP_OKAY;
12654 }
12655 
12656 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12657 static
12658 SCIP_DECL_CONSFREE(consFreeCumulative)
12659 { /*lint --e{715}*/
12660  SCIP_CONSHDLRDATA* conshdlrdata;
12661 
12662  assert(conshdlr != NULL);
12663  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12664 
12665  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12666  assert(conshdlrdata != NULL);
12667 
12668 #ifdef SCIP_STATISTIC
12669  if( !conshdlrdata->iscopy )
12670  {
12671  /* statisitc output if SCIP_STATISTIC is defined */
12672  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12673  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12674  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12675  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12676  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12677  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12678  }
12679 #endif
12680 
12681  conshdlrdataFree(scip, &conshdlrdata);
12682 
12683  SCIPconshdlrSetData(conshdlr, NULL);
12684 
12685  return SCIP_OKAY;
12686 }
12687 
12688 
12689 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12690 static
12691 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12692 { /*lint --e{715}*/
12693  SCIP_CONSHDLRDATA* conshdlrdata;
12694  int c;
12695 
12696  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12697  assert(conshdlrdata != NULL);
12698 
12699  conshdlrdata->detectedredundant = FALSE;
12700 
12701  for( c = 0; c < nconss; ++c )
12702  {
12703  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12704  * hmax)
12705  */
12706  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12707  }
12708 
12709  return SCIP_OKAY;
12710 }
12711 
12712 
12713 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12714 #ifdef SCIP_STATISTIC
12715 static
12716 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12717 { /*lint --e{715}*/
12718  SCIP_CONSHDLRDATA* conshdlrdata;
12719  int c;
12720 
12721  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12722  assert(conshdlrdata != NULL);
12723 
12724  for( c = 0; c < nconss; ++c )
12725  {
12726  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12727 
12728 #if 0
12729  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12730 #endif
12731  }
12732 
12733  if( !conshdlrdata->iscopy )
12734  {
12735  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12736  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12737  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12738  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12739  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12740  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12741  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12742  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12743  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12744  }
12745 
12746  return SCIP_OKAY;
12747 }
12748 #endif
12749 
12750 
12751 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12752 static
12753 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12754 { /*lint --e{715}*/
12755  SCIP_CONSDATA* consdata;
12756  int c;
12757 
12758  assert(conshdlr != NULL);
12759  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12760 
12761  /* release the rows of all constraints */
12762  for( c = 0; c < nconss; ++c )
12763  {
12764  consdata = SCIPconsGetData(conss[c]);
12765  assert(consdata != NULL);
12766 
12767  /* free rows */
12768  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12769  }
12770 
12771  return SCIP_OKAY;
12772 }
12773 
12774 /** frees specific constraint data */
12775 static
12776 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12777 { /*lint --e{715}*/
12778  assert(conshdlr != NULL);
12779  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12780  assert(consdata != NULL );
12781  assert(*consdata != NULL );
12782 
12783  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12784  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12785  {
12786  SCIP_CONSHDLRDATA* conshdlrdata;
12787 
12788  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12789  assert(conshdlrdata != NULL);
12790 
12791  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12792  }
12793 
12794  /* free cumulative constraint data */
12795  SCIP_CALL( consdataFree(scip, consdata) );
12796 
12797  return SCIP_OKAY;
12798 }
12799 
12800 /** transforms constraint data into data belonging to the transformed problem */
12801 static
12802 SCIP_DECL_CONSTRANS(consTransCumulative)
12803 { /*lint --e{715}*/
12804  SCIP_CONSHDLRDATA* conshdlrdata;
12805  SCIP_CONSDATA* sourcedata;
12806  SCIP_CONSDATA* targetdata;
12807 
12808  assert(conshdlr != NULL);
12809  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12810  assert(sourcecons != NULL);
12811  assert(targetcons != NULL);
12812 
12813  sourcedata = SCIPconsGetData(sourcecons);
12814  assert(sourcedata != NULL);
12815  assert(sourcedata->demandrows == NULL);
12816 
12817  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12818 
12819  /* get event handler */
12820  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12821  assert(conshdlrdata != NULL);
12822  assert(conshdlrdata->eventhdlr != NULL);
12823 
12824  /* create constraint data for target constraint */
12825  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12826  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12827  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12828 
12829  /* create target constraint */
12830  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12831  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12832  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12833  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12834  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12835 
12836  /* catch bound change events of variables */
12837  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12838 
12839  return SCIP_OKAY;
12840 }
12841 
12842 /** LP initialization method of constraint handler */
12843 static
12844 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12846  SCIP_CONSHDLRDATA* conshdlrdata;
12847  int c;
12848 
12849  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12850  assert(conshdlr != NULL);
12851  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12852  assert(conshdlrdata != NULL);
12853 
12854  *infeasible = FALSE;
12855 
12856  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12857 
12858  if( conshdlrdata->usebinvars )
12859  {
12860  /* add rows to LP */
12861  for( c = 0; c < nconss && !(*infeasible); ++c )
12862  {
12863  assert(SCIPconsIsInitial(conss[c]));
12864  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12865 
12866  if( conshdlrdata->cutsasconss )
12867  {
12868  SCIP_CALL( SCIPrestartSolve(scip) );
12869  }
12870  }
12871  }
12872 
12873  /**@todo if we want to use only the integer variables; only these will be in cuts
12874  * create some initial cuts, currently these are only separated */
12875 
12876  return SCIP_OKAY;
12877 }
12878 
12879 /** separation method of constraint handler for LP solutions */
12880 static
12881 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12883  SCIP_CONSHDLRDATA* conshdlrdata;
12884  SCIP_Bool cutoff;
12885  SCIP_Bool separated;
12886  int c;
12887 
12888  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12889 
12890  assert(conshdlr != NULL);
12891  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12892  assert(nconss == 0 || conss != NULL);
12893  assert(result != NULL);
12894  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12895  assert(conshdlrdata != NULL);
12896 
12897  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12898 
12899  cutoff = FALSE;
12900  separated = FALSE;
12901  (*result) = SCIP_DIDNOTRUN;
12902 
12903  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12904  return SCIP_OKAY;
12905 
12906  (*result) = SCIP_DIDNOTFIND;
12907 
12908  if( conshdlrdata->usebinvars )
12909  {
12910  /* check all useful cumulative constraints for feasibility */
12911  for( c = 0; c < nusefulconss && !cutoff; ++c )
12912  {
12913  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12914  }
12915 
12916  if( !cutoff && conshdlrdata->usecovercuts )
12917  {
12918  for( c = 0; c < nusefulconss; ++c )
12919  {
12920  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12921  }
12922  }
12923  }
12924 
12925  if( conshdlrdata->sepaold )
12926  {
12927  /* separate cuts containing only integer variables */
12928  for( c = 0; c < nusefulconss; ++c )
12929  {
12930  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12931  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12932  }
12933  }
12934 
12935  if( cutoff )
12936  *result = SCIP_CUTOFF;
12937  else if( separated )
12938  *result = SCIP_SEPARATED;
12939 
12940  return SCIP_OKAY;
12941 }
12942 
12943 /** separation method of constraint handler for arbitrary primal solutions */
12944 static
12945 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12946 { /*lint --e{715}*/
12947  SCIP_CONSHDLRDATA* conshdlrdata;
12948  SCIP_Bool cutoff;
12949  SCIP_Bool separated;
12950  int c;
12951 
12952  assert(conshdlr != NULL);
12953  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12954  assert(nconss == 0 || conss != NULL);
12955  assert(result != NULL);
12956 
12957  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12958  assert(conshdlrdata != NULL);
12959 
12960  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12961  return SCIP_OKAY;
12962 
12963  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12964 
12965  cutoff = FALSE;
12966  separated = FALSE;
12967  (*result) = SCIP_DIDNOTFIND;
12968 
12969  if( conshdlrdata->usebinvars )
12970  {
12971  /* check all useful cumulative constraints for feasibility */
12972  for( c = 0; c < nusefulconss && !cutoff; ++c )
12973  {
12974  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12975  }
12976 
12977  if( !cutoff && conshdlrdata->usecovercuts )
12978  {
12979  for( c = 0; c < nusefulconss; ++c )
12980  {
12981  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12982  }
12983  }
12984  }
12985  if( conshdlrdata->sepaold )
12986  {
12987  /* separate cuts containing only integer variables */
12988  for( c = 0; c < nusefulconss; ++c )
12989  {
12990  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12991  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12992  }
12993  }
12994 
12995  if( cutoff )
12996  *result = SCIP_CUTOFF;
12997  else if( separated )
12998  *result = SCIP_SEPARATED;
12999 
13000  return SCIP_OKAY;
13001 }
13002 
13003 /** constraint enforcing method of constraint handler for LP solutions */
13004 static
13005 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
13006 { /*lint --e{715}*/
13007  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
13008 
13009  return SCIP_OKAY;
13010 }
13011 
13012 /** constraint enforcing method of constraint handler for relaxation solutions */
13013 static
13014 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
13015 { /*lint --e{715}*/
13016  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
13017 
13018  return SCIP_OKAY;
13019 }
13020 
13021 /** constraint enforcing method of constraint handler for pseudo solutions */
13022 static
13023 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
13024 { /*lint --e{715}*/
13025  SCIP_CONSHDLRDATA* conshdlrdata;
13026 
13027  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13028 
13029  assert(conshdlr != NULL);
13030  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13031  assert(nconss == 0 || conss != NULL);
13032  assert(result != NULL);
13033 
13034  if( objinfeasible )
13035  {
13036  *result = SCIP_DIDNOTRUN;
13037  return SCIP_OKAY;
13038  }
13039 
13040  (*result) = SCIP_FEASIBLE;
13041 
13042  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13043  assert(conshdlrdata != NULL);
13044 
13045  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13046 
13047  return SCIP_OKAY;
13048 }
13049 
13050 /** feasibility check method of constraint handler for integral solutions */
13051 static
13052 SCIP_DECL_CONSCHECK(consCheckCumulative)
13053 { /*lint --e{715}*/
13054  int c;
13055 
13056  assert(conshdlr != NULL);
13057  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13058  assert(nconss == 0 || conss != NULL);
13059  assert(result != NULL);
13060 
13061  *result = SCIP_FEASIBLE;
13062 
13063  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13064 
13065  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13066  {
13067  SCIP_Bool violated = FALSE;
13068 
13069  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13070 
13071  if( violated )
13072  *result = SCIP_INFEASIBLE;
13073  }
13074 
13075  return SCIP_OKAY;
13076 }
13077 
13078 /** domain propagation method of constraint handler */
13079 static
13080 SCIP_DECL_CONSPROP(consPropCumulative)
13081 { /*lint --e{715}*/
13082  SCIP_CONSHDLRDATA* conshdlrdata;
13083  SCIP_Bool cutoff;
13084  int nchgbds;
13085  int ndelconss;
13086  int c;
13087 #if 0
13088  int naggrvars = 0;
13089 #endif
13090 
13091  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13092 
13093  assert(conshdlr != NULL);
13094  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13095  assert(nconss == 0 || conss != NULL);
13096  assert(result != NULL);
13097 
13098  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13099  assert(conshdlrdata != NULL);
13100 
13101  nchgbds = 0;
13102  ndelconss = 0;
13103  cutoff = FALSE;
13104  (*result) = SCIP_DIDNOTRUN;
13105 
13106  /* propgate all useful constraints */
13107  for( c = 0; c < nusefulconss && !cutoff; ++c )
13108  {
13109  SCIP_CONS* cons;
13110 
13111  cons = conss[c];
13112  assert(cons != NULL);
13113 
13114  if( SCIPgetDepth(scip) == 0 )
13115  {
13116 #if 0
13117  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13118  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13119 #else
13120  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13121  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13122 #endif
13123  if( cutoff )
13124  break;
13125 
13126  if( SCIPconsIsDeleted(cons) )
13127  continue;
13128  }
13129 
13130  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13131  }
13132 
13133  if( !cutoff && nchgbds == 0 )
13134  {
13135  /* propgate all other constraints */
13136  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13137  {
13138  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13139  }
13140  }
13141 
13142 #if 0
13143  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13144  {
13145  SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13146  }
13147 #endif
13148 
13149  if( cutoff )
13150  {
13151  SCIPdebugMsg(scip, "detected infeasible\n");
13152  *result = SCIP_CUTOFF;
13153  }
13154  else if( nchgbds > 0 )
13155  {
13156  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13157  *result = SCIP_REDUCEDDOM;
13158  }
13159  else
13160  *result = SCIP_DIDNOTFIND;
13161 
13162  return SCIP_OKAY;
13163 }
13164 
13165 /** presolving method of constraint handler */
13166 static
13167 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13168 { /*lint --e{715}*/
13169  SCIP_CONSHDLRDATA* conshdlrdata;
13170  SCIP_CONS* cons;
13171  SCIP_Bool cutoff;
13172  SCIP_Bool unbounded;
13173  int oldnfixedvars;
13174  int oldnchgbds;
13175  int oldndelconss;
13176  int oldnaddconss;
13177  int oldnupgdconss;
13178  int oldnchgsides;
13179  int oldnchgcoefs;
13180  int c;
13181 
13182  assert(conshdlr != NULL);
13183  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13184  assert(scip != NULL);
13185  assert(result != NULL);
13186 
13187  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13188 
13189  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13190  assert(conshdlrdata != NULL);
13191 
13192  *result = SCIP_DIDNOTRUN;
13193 
13194  oldnfixedvars = *nfixedvars;
13195  oldnchgbds = *nchgbds;
13196  oldnchgsides = *nchgsides;
13197  oldnchgcoefs = *nchgcoefs;
13198  oldnupgdconss = *nupgdconss;
13199  oldndelconss = *ndelconss;
13200  oldnaddconss = *naddconss;
13201  cutoff = FALSE;
13202  unbounded = FALSE;
13203 
13204  /* process constraints */
13205  for( c = 0; c < nconss && !cutoff; ++c )
13206  {
13207  cons = conss[c];
13208 
13209  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13210  * hmax)
13211  */
13212  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13213 
13214  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13215  {
13216 #if 0
13217  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13218  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13219 #else
13220  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13221  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13222 #endif
13223 
13224  if( cutoff || unbounded )
13225  break;
13226 
13227  if( SCIPconsIsDeleted(cons) )
13228  continue;
13229  }
13230 
13231  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13232  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13233  {
13234  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13235  }
13236 
13237  /* strengthen existing variable bounds using the cumulative condition */
13238  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13239  {
13240  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13241  }
13242 
13243  /* propagate cumulative constraint */
13244  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13245  assert(checkDemands(scip, cons) || cutoff);
13246  }
13247 
13248  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13249  {
13250  SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13251  }
13252 
13253  /* only perform the detection of variable bounds and disjunctive constraint once */
13254  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13255  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13256  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13257  {
13258  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13259  * propagation
13260  */
13261  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13262  conshdlrdata->detectedredundant = TRUE;
13263  }
13264 
13265  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13266  {
13267  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13268  }
13269 
13270  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13271  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13272 
13273  if( cutoff )
13274  *result = SCIP_CUTOFF;
13275  else if( unbounded )
13276  *result = SCIP_UNBOUNDED;
13277  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13278  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13279  *result = SCIP_SUCCESS;
13280  else
13281  *result = SCIP_DIDNOTFIND;
13282 
13283  return SCIP_OKAY;
13284 }
13285 
13286 /** propagation conflict resolving method of constraint handler */
13287 static
13288 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13289 { /*lint --e{715}*/
13290  SCIP_CONSHDLRDATA* conshdlrdata;
13291  SCIP_CONSDATA* consdata;
13292 
13293  assert(conshdlr != NULL);
13294  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13295  assert(scip != NULL);
13296  assert(result != NULL);
13297  assert(infervar != NULL);
13298  assert(bdchgidx != NULL);
13299 
13300  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13301  assert(conshdlrdata != NULL);
13302 
13303  /* process constraint */
13304  assert(cons != NULL);
13305 
13306  consdata = SCIPconsGetData(cons);
13307  assert(consdata != NULL);
13308 
13309  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13310  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13311  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13312 
13313  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13314  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13315  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13316 
13317  return SCIP_OKAY;
13318 }
13319 
13320 /** variable rounding lock method of constraint handler */
13321 static
13322 SCIP_DECL_CONSLOCK(consLockCumulative)
13323 { /*lint --e{715}*/
13324  SCIP_CONSDATA* consdata;
13325  SCIP_VAR** vars;
13326  int v;
13327 
13328  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13329 
13330  assert(scip != NULL);
13331  assert(cons != NULL);
13332  assert(locktype == SCIP_LOCKTYPE_MODEL);
13333 
13334  consdata = SCIPconsGetData(cons);
13335  assert(consdata != NULL);
13336 
13337  vars = consdata->vars;
13338  assert(vars != NULL);
13339 
13340  for( v = 0; v < consdata->nvars; ++v )
13341  {
13342  if( consdata->downlocks[v] && consdata->uplocks[v] )
13343  {
13344  /* the integer start variable should not get rounded in both direction */
13345  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13346  }
13347  else if( consdata->downlocks[v] )
13348  {
13349  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13350  }
13351  else if( consdata->uplocks[v] )
13352  {
13353  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13354  }
13355  }
13356 
13357  return SCIP_OKAY;
13358 }
13359 
13360 
13361 /** constraint display method of constraint handler */
13362 static
13363 SCIP_DECL_CONSPRINT(consPrintCumulative)
13364 { /*lint --e{715}*/
13365  assert(scip != NULL);
13366  assert(conshdlr != NULL);
13367  assert(cons != NULL);
13368 
13369  consdataPrint(scip, SCIPconsGetData(cons), file);
13370 
13371  return SCIP_OKAY;
13372 }
13373 
13374 /** constraint copying method of constraint handler */
13375 static
13376 SCIP_DECL_CONSCOPY(consCopyCumulative)
13377 { /*lint --e{715}*/
13378  SCIP_CONSDATA* sourceconsdata;
13379  SCIP_VAR** sourcevars;
13380  SCIP_VAR** vars;
13381  const char* consname;
13382 
13383  int nvars;
13384  int v;
13385 
13386  sourceconsdata = SCIPconsGetData(sourcecons);
13387  assert(sourceconsdata != NULL);
13388 
13389  /* get variables of the source constraint */
13390  nvars = sourceconsdata->nvars;
13391  sourcevars = sourceconsdata->vars;
13392 
13393  (*valid) = TRUE;
13394 
13395  if( nvars == 0 )
13396  return SCIP_OKAY;
13397 
13398  /* allocate buffer array */
13399  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13400 
13401  for( v = 0; v < nvars && *valid; ++v )
13402  {
13403  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13404  assert(!(*valid) || vars[v] != NULL);
13405  }
13406 
13407  /* only create the target constraint, if all variables could be copied */
13408  if( *valid )
13409  {
13410  if( name != NULL )
13411  consname = name;
13412  else
13413  consname = SCIPconsGetName(sourcecons);
13414 
13415  /* create a copy of the cumulative constraint */
13416  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13417  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13418  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13419 
13420  /* adjust left side if the time axis if needed */
13421  if( sourceconsdata->hmin > 0 )
13422  {
13423  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13424  }
13425 
13426  /* adjust right side if the time axis if needed */
13427  if( sourceconsdata->hmax < INT_MAX )
13428  {
13429  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13430  }
13431  }
13432 
13433  /* free buffer array */
13434  SCIPfreeBufferArray(scip, &vars);
13435 
13436  return SCIP_OKAY;
13437 }
13438 
13439 
13440 /** constraint parsing method of constraint handler */
13441 static
13442 SCIP_DECL_CONSPARSE(consParseCumulative)
13443 { /*lint --e{715}*/
13444  SCIP_VAR** vars;
13445  SCIP_VAR* var;
13446  SCIP_Real value;
13447  char strvalue[SCIP_MAXSTRLEN];
13448  char* endptr;
13449  int* demands;
13450  int* durations;
13451  int capacity;
13452  int duration;
13453  int demand;
13454  int hmin;
13455  int hmax;
13456  int varssize;
13457  int nvars;
13458 
13459  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13460 
13461  /* cutoff "cumulative" form the constraint string */
13462  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13463  str = endptr;
13464 
13465  varssize = 100;
13466  nvars = 0;
13467 
13468  /* allocate buffer array for variables */
13469  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13470  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13471  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13472 
13473  do
13474  {
13475  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13476 
13477  if( var != NULL )
13478  {
13479  str = endptr;
13480 
13481  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13482  duration = atoi(strvalue);
13483  str = endptr;
13484 
13485  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13486  demand = atoi(strvalue);
13487  str = endptr;
13488 
13489  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13490 
13491  vars[nvars] = var;
13492  demands[nvars] = demand;
13493  durations[nvars] = duration;
13494  nvars++;
13495  }
13496  }
13497  while( var != NULL );
13498 
13499  /* parse effective time window */
13500  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13501  hmin = atoi(strvalue);
13502  str = endptr;
13503 
13504  if( SCIPstrToRealValue(str, &value, &endptr) )
13505  {
13506  hmax = (int)(value);
13507  str = endptr;
13508 
13509  /* parse capacity */
13510  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13511  str = endptr;
13512  if( SCIPstrToRealValue(str, &value, &endptr) )
13513  {
13514  capacity = (int)value;
13515 
13516  /* create cumulative constraint */
13517  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13518  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13519 
13520  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13521  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13522 
13523  (*success) = TRUE;
13524  }
13525  }
13526 
13527  /* free buffer arrays */
13528  SCIPfreeBufferArray(scip, &durations);
13529  SCIPfreeBufferArray(scip, &demands);
13530  SCIPfreeBufferArray(scip, &vars);
13531 
13532  return SCIP_OKAY;
13533 }
13534 
13535 /** constraint method of constraint handler which returns the variables (if possible) */
13536 static
13537 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13538 { /*lint --e{715}*/
13539  SCIP_CONSDATA* consdata;
13540 
13541  consdata = SCIPconsGetData(cons);
13542  assert(consdata != NULL);
13543 
13544  if( varssize < consdata->nvars )
13545  (*success) = FALSE;
13546  else
13547  {
13548  assert(vars != NULL);
13549 
13550  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13551  (*success) = TRUE;
13552  }
13553 
13554  return SCIP_OKAY;
13555 }
13556 
13557 /** constraint method of constraint handler which returns the number of variables (if possible) */
13558 static
13559 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13560 { /*lint --e{715}*/
13561  SCIP_CONSDATA* consdata;
13562 
13563  consdata = SCIPconsGetData(cons);
13564  assert(consdata != NULL);
13565 
13566  (*nvars) = consdata->nvars;
13567  (*success) = TRUE;
13568 
13569  return SCIP_OKAY;
13570 }
13571 
13572 /**@} */
13573 
13574 /**@name Callback methods of event handler
13575  *
13576  * @{
13577  */
13578 
13579 
13580 /** execution method of event handler */
13581 static
13582 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13583 { /*lint --e{715}*/
13584  SCIP_CONSDATA* consdata;
13585 
13586  assert(scip != NULL);
13587  assert(eventhdlr != NULL);
13588  assert(eventdata != NULL);
13589  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13590  assert(event != NULL);
13591 
13592  consdata = (SCIP_CONSDATA*)eventdata;
13593  assert(consdata != NULL);
13594 
13595  /* mark the constraint to be not propagated */
13596  consdata->propagated = FALSE;
13597 
13598  return SCIP_OKAY;
13599 }
13600 
13601 /**@} */
13602 
13603 /*
13604  * constraint specific interface methods
13605  */
13606 
13607 /** creates the handler for cumulative constraints and includes it in SCIP */
13609  SCIP* scip /**< SCIP data structure */
13610  )
13611 {
13612  SCIP_CONSHDLRDATA* conshdlrdata;
13613  SCIP_CONSHDLR* conshdlr;
13614  SCIP_EVENTHDLR* eventhdlr;
13615 
13616  /* create event handler for bound change events */
13617  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13618 
13619  /* create cumulative constraint handler data */
13620  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13621 
13622  /* include constraint handler */
13625  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13626  conshdlrdata) );
13627 
13628  assert(conshdlr != NULL);
13629 
13630  /* set non-fundamental callbacks via specific setter functions */
13631  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13632  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13633 #ifdef SCIP_STATISTIC
13634  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13635 #endif
13636  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13637  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13638  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13639  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13640  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13641  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13642  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13643  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13645  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13646  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13648  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13649  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13651  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13652  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13653 
13654  /* add cumulative constraint handler parameters */
13656  "constraints/" CONSHDLR_NAME "/ttinfer",
13657  "should time-table (core-times) propagator be used to infer bounds?",
13658  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13660  "constraints/" CONSHDLR_NAME "/efcheck",
13661  "should edge-finding be used to detect an overload?",
13662  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13664  "constraints/" CONSHDLR_NAME "/efinfer",
13665  "should edge-finding be used to infer bounds?",
13666  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13668  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13669  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13671  "constraints/" CONSHDLR_NAME "/ttefcheck",
13672  "should time-table edge-finding be used to detect an overload?",
13673  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13675  "constraints/" CONSHDLR_NAME "/ttefinfer",
13676  "should time-table edge-finding be used to infer bounds?",
13677  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13678 
13680  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13681  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13683  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13684  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13686  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13687  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13689  "constraints/" CONSHDLR_NAME "/cutsasconss",
13690  "should the cumulative constraint create cuts as knapsack constraints?",
13691  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13693  "constraints/" CONSHDLR_NAME "/sepaold",
13694  "shall old sepa algo be applied?",
13695  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13696 
13698  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13699  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13700 
13701  /* presolving parameters */
13703  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13704  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13706  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13707  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13709  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13710  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13712  "constraints/" CONSHDLR_NAME "/presolpairwise",
13713  "should pairwise constraint comparison be performed in presolving?",
13714  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13716  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13717  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13718 
13720  "constraints/" CONSHDLR_NAME "/maxnodes",
13721  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13722  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13724  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13725  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13727  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13728  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13729 
13730  /* conflict analysis parameters */
13732  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13733  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13734 
13735  return SCIP_OKAY;
13736 }
13737 
13738 /** creates and captures a cumulative constraint */
13740  SCIP* scip, /**< SCIP data structure */
13741  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13742  const char* name, /**< name of constraint */
13743  int nvars, /**< number of variables (jobs) */
13744  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13745  int* durations, /**< array containing corresponding durations */
13746  int* demands, /**< array containing corresponding demands */
13747  int capacity, /**< available cumulative capacity */
13748  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13749  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13750  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13751  * Usually set to TRUE. */
13752  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13753  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13754  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13755  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13756  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13757  * Usually set to TRUE. */
13758  SCIP_Bool local, /**< is constraint only valid locally?
13759  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13760  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13761  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13762  * adds coefficients to this constraint. */
13763  SCIP_Bool dynamic, /**< is constraint subject to aging?
13764  * Usually set to FALSE. Set to TRUE for own cuts which
13765  * are seperated as constraints. */
13766  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13767  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13768  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13769  * if it may be moved to a more global node?
13770  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13771  )
13772 {
13773  SCIP_CONSHDLR* conshdlr;
13774  SCIP_CONSDATA* consdata;
13775 
13776  assert(scip != NULL);
13777 
13778  /* find the cumulative constraint handler */
13779  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13780  if( conshdlr == NULL )
13781  {
13782  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13783  return SCIP_PLUGINNOTFOUND;
13784  }
13785 
13786  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13787 
13788  /* create constraint data */
13789  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13790 
13791  /* create constraint */
13792  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13793  initial, separate, enforce, check, propagate,
13794  local, modifiable, dynamic, removable, stickingatnode) );
13795 
13796  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13797  {
13798  SCIP_CONSHDLRDATA* conshdlrdata;
13799 
13800  /* get event handler */
13801  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13802  assert(conshdlrdata != NULL);
13803  assert(conshdlrdata->eventhdlr != NULL);
13804 
13805  /* catch bound change events of variables */
13806  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13807  }
13808 
13809  return SCIP_OKAY;
13810 }
13811 
13812 /** creates and captures a cumulative constraint
13813  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13814  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13815  *
13816  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13817  *
13818  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13819  */
13821  SCIP* scip, /**< SCIP data structure */
13822  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13823  const char* name, /**< name of constraint */
13824  int nvars, /**< number of variables (jobs) */
13825  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13826  int* durations, /**< array containing corresponding durations */
13827  int* demands, /**< array containing corresponding demands */
13828  int capacity /**< available cumulative capacity */
13829  )
13830 {
13831  assert(scip != NULL);
13832 
13833  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13834  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13835 
13836  return SCIP_OKAY;
13837 }
13838 
13839 /** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13841  SCIP* scip, /**< SCIP data structure */
13842  SCIP_CONS* cons, /**< constraint data */
13843  int hmin /**< left bound of time axis to be considered */
13844  )
13845 {
13846  SCIP_CONSDATA* consdata;
13847  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13848  {
13849  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13850  return SCIP_INVALIDCALL;
13851  }
13852 
13853  consdata = SCIPconsGetData(cons);
13854  assert(consdata != NULL);
13855  assert(hmin >= 0);
13856  assert(hmin <= consdata->hmax);
13857 
13858  consdata->hmin = hmin;
13859 
13860  return SCIP_OKAY;
13861 }
13862 
13863 /** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13865  SCIP* scip, /**< SCIP data structure */
13866  SCIP_CONS* cons /**< constraint */
13867  )
13868 {
13869  SCIP_CONSDATA* consdata;
13870  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13871  {
13872  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13873  SCIPABORT();
13874  return 0; /*lint !e527*/
13875  }
13876 
13877  consdata = SCIPconsGetData(cons);
13878  assert(consdata != NULL);
13879 
13880  return consdata->hmin;
13881 }
13882 
13883 /** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13885  SCIP* scip, /**< SCIP data structure */
13886  SCIP_CONS* cons, /**< constraint data */
13887  int hmax /**< right bound of time axis to be considered */
13888  )
13889 {
13890  SCIP_CONSDATA* consdata;
13891  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13892  {
13893  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13894  SCIPABORT();
13895  return SCIP_INVALIDCALL; /*lint !e527*/
13896  }
13897 
13898  consdata = SCIPconsGetData(cons);
13899  assert(consdata != NULL);
13900  assert(hmax >= consdata->hmin);
13901 
13902  consdata->hmax = hmax;
13903 
13904  return SCIP_OKAY;
13905 }
13906 
13907 /** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13909  SCIP* scip, /**< SCIP data structure */
13910  SCIP_CONS* cons /**< constraint */
13911  )
13912 {
13913  SCIP_CONSDATA* consdata;
13914  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13915  {
13916  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13917  SCIPABORT();
13918  return 0; /*lint !e527*/
13919  }
13920 
13921  consdata = SCIPconsGetData(cons);
13922  assert(consdata != NULL);
13923 
13924  return consdata->hmax;
13925 }
13926 
13927 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13929  SCIP* scip, /**< SCIP data structure */
13930  SCIP_CONS* cons /**< constraint data */
13931  )
13932 {
13933  SCIP_CONSDATA* consdata;
13934 
13935  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13936  {
13937  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13938  SCIPABORT();
13939  return NULL; /*lint !e527*/
13940  }
13941 
13942  consdata = SCIPconsGetData(cons);
13943  assert(consdata != NULL);
13944 
13945  return consdata->vars;
13946 }
13947 
13948 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13950  SCIP* scip, /**< SCIP data structure */
13951  SCIP_CONS* cons /**< constraint data */
13952  )
13953 {
13954  SCIP_CONSDATA* consdata;
13955 
13956  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13957  {
13958  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13959  SCIPABORT();
13960  return -1; /*lint !e527*/
13961  }
13962 
13963  consdata = SCIPconsGetData(cons);
13964  assert(consdata != NULL);
13965 
13966  return consdata->nvars;
13967 }
13968 
13969 /** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13971  SCIP* scip, /**< SCIP data structure */
13972  SCIP_CONS* cons /**< constraint data */
13973  )
13974 {
13975  SCIP_CONSDATA* consdata;
13976 
13977  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13978  {
13979  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13980  SCIPABORT();
13981  return -1; /*lint !e527*/
13982  }
13983 
13984  consdata = SCIPconsGetData(cons);
13985  assert(consdata != NULL);
13986 
13987  return consdata->capacity;
13988 }
13989 
13990 /** returns the durations of the cumulative constraint */ /*lint -e{715}*/
13992  SCIP* scip, /**< SCIP data structure */
13993  SCIP_CONS* cons /**< constraint data */
13994  )
13995 {
13996  SCIP_CONSDATA* consdata;
13997 
13998  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13999  {
14000  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14001  SCIPABORT();
14002  return NULL; /*lint !e527*/
14003  }
14004 
14005  consdata = SCIPconsGetData(cons);
14006  assert(consdata != NULL);
14007 
14008  return consdata->durations;
14009 }
14010 
14011 /** returns the demands of the cumulative constraint */ /*lint -e{715}*/
14013  SCIP* scip, /**< SCIP data structure */
14014  SCIP_CONS* cons /**< constraint data */
14015  )
14016 {
14017  SCIP_CONSDATA* consdata;
14018 
14019  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14020  {
14021  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14022  SCIPABORT();
14023  return NULL; /*lint !e527*/
14024  }
14025 
14026  consdata = SCIPconsGetData(cons);
14027  assert(consdata != NULL);
14028 
14029  return consdata->demands;
14030 }
14031 
14032 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14033  * given solution is satisfied
14034  */
14036  SCIP* scip, /**< SCIP data structure */
14037  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14038  int nvars, /**< number of variables (jobs) */
14039  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14040  int* durations, /**< array containing corresponding durations */
14041  int* demands, /**< array containing corresponding demands */
14042  int capacity, /**< available cumulative capacity */
14043  int hmin, /**< left bound of time axis to be considered (including hmin) */
14044  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14045  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14046  SCIP_CONS* cons, /**< constraint which is checked */
14047  SCIP_Bool printreason /**< should the reason for the violation be printed? */
14048  )
14049 {
14050  assert(scip != NULL);
14051  assert(violated != NULL);
14052 
14053  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14054  violated, cons, printreason) );
14055 
14056  return SCIP_OKAY;
14057 }
14058 
14059 /** normalize cumulative condition */ /*lint -e{715}*/
14061  SCIP* scip, /**< SCIP data structure */
14062  int nvars, /**< number of start time variables (activities) */
14063  SCIP_VAR** vars, /**< array of start time variables */
14064  int* durations, /**< array of durations */
14065  int* demands, /**< array of demands */
14066  int* capacity, /**< pointer to store the changed cumulative capacity */
14067  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14068  int* nchgsides /**< pointer to count number of side changes */
14069  )
14070 { /*lint --e{715}*/
14071  normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14072 
14073  return SCIP_OKAY;
14074 }
14075 
14076 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14078  SCIP* scip, /**< SCIP data structure */
14079  int nvars, /**< number of variables (jobs) */
14080  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14081  int* durations, /**< array containing corresponding durations */
14082  int* demands, /**< array containing corresponding demands */
14083  int capacity, /**< available cumulative capacity */
14084  int* hmin, /**< pointer to store the left bound of the effective horizon */
14085  int* hmax, /**< pointer to store the right bound of the effective horizon */
14086  int* split /**< point were the cumulative condition can be split */
14087  )
14088 {
14089  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14090  hmin, hmax, split) );
14091 
14092  return SCIP_OKAY;
14093 }
14094 
14095 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14097  SCIP* scip, /**< SCIP data structure */
14098  int nvars, /**< number of start time variables (activities) */
14099  SCIP_VAR** vars, /**< array of start time variables */
14100  int* durations, /**< array of durations */
14101  int hmin, /**< left bound of time axis to be considered */
14102  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14103  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14104  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14105  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14106  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14107  int* nfixedvars, /**< pointer to store the number of fixed variables */
14108  int* nchgsides, /**< pointer to store the number of changed sides */
14109  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14110  )
14111 {
14112  if( nvars <= 1 )
14113  return SCIP_OKAY;
14114 
14115  /* presolve constraint form the earlier start time point of view */
14116  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14117  irrelevants, nfixedvars, nchgsides, cutoff) );
14118 
14119  /* presolve constraint form the latest completion time point of view */
14120  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14121  irrelevants, nfixedvars, nchgsides, cutoff) );
14122 
14123  return SCIP_OKAY;
14124 }
14125 
14126 /** propagate the given cumulative condition */
14128  SCIP* scip, /**< SCIP data structure */
14129  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14130  int nvars, /**< number of variables (jobs) */
14131  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14132  int* durations, /**< array containing corresponding durations */
14133  int* demands, /**< array containing corresponding demands */
14134  int capacity, /**< available cumulative capacity */
14135  int hmin, /**< left bound of time axis to be considered (including hmin) */
14136  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14137  SCIP_CONS* cons, /**< constraint which gets propagated */
14138  int* nchgbds, /**< pointer to store the number of variable bound changes */
14139  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14140  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14141  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14142  )
14143 {
14144  SCIP_CONSHDLR* conshdlr;
14145  SCIP_CONSHDLRDATA* conshdlrdata;
14146  SCIP_Bool redundant;
14147 
14148  assert(scip != NULL);
14149  assert(cons != NULL);
14150  assert(initialized != NULL);
14151  assert(*initialized == FALSE);
14152  assert(cutoff != NULL);
14153  assert(*cutoff == FALSE);
14154 
14155  /* find the cumulative constraint handler */
14156  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14157  if( conshdlr == NULL )
14158  {
14159  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14160  return SCIP_PLUGINNOTFOUND;
14161  }
14162 
14163  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14164  assert(conshdlrdata != NULL);
14165 
14166  redundant = FALSE;
14167 
14168  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14169  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14170  nchgbds, &redundant, initialized, explanation, cutoff) );
14171 
14172  return SCIP_OKAY;
14173 }
14174 
14175 /** resolve propagation w.r.t. the cumulative condition */
14177  SCIP* scip, /**< SCIP data structure */
14178  int nvars, /**< number of start time variables (activities) */
14179  SCIP_VAR** vars, /**< array of start time variables */
14180  int* durations, /**< array of durations */
14181  int* demands, /**< array of demands */
14182  int capacity, /**< cumulative capacity */
14183  int hmin, /**< left bound of time axis to be considered (including hmin) */
14184  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14185  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14186  int inferinfo, /**< the user information */
14187  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14188  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14189  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14190  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14191  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14192  )
14193 {
14194  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14195  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14196 
14197  return SCIP_OKAY;
14198 }
14199 
14200 /** this method visualizes the cumulative structure in GML format */
14202  SCIP* scip, /**< SCIP data structure */
14203  SCIP_CONS* cons /**< cumulative constraint */
14204  )
14205 {
14206  SCIP_CONSDATA* consdata;
14207  SCIP_HASHTABLE* vars;
14208  FILE* file;
14209  SCIP_VAR* var;
14210  char filename[SCIP_MAXSTRLEN];
14211  int nvars;
14212  int v;
14213 
14214  SCIP_RETCODE retcode = SCIP_OKAY;
14215 
14216  /* open file */
14217  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14218  file = fopen(filename, "w");
14219 
14220  /* check if the file was open */
14221  if( file == NULL )
14222  {
14223  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14224  SCIPprintSysError(filename);
14225  return SCIP_FILECREATEERROR;
14226  }
14227 
14228  consdata = SCIPconsGetData(cons);
14229  assert(consdata != NULL);
14230 
14231  nvars = consdata->nvars;
14232 
14233  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14234  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14235 
14236  /* create opening of the GML format */
14237  SCIPgmlWriteOpening(file, TRUE);
14238 
14239  for( v = 0; v < nvars; ++v )
14240  {
14241  char color[SCIP_MAXSTRLEN];
14242 
14243  var = consdata->vars[v];
14244  assert(var != NULL);
14245 
14246  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14247 
14248  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14249  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14250  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14251  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14252  else
14253  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14254 
14255  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14256  }
14257 
14258  for( v = 0; v < nvars; ++v )
14259  {
14260  SCIP_VAR** vbdvars;
14261  int nvbdvars;
14262  int b;
14263 
14264  var = consdata->vars[v];
14265  assert(var != NULL);
14266 
14267  vbdvars = SCIPvarGetVlbVars(var);
14268  nvbdvars = SCIPvarGetNVlbs(var);
14269 
14270  for( b = 0; b < nvbdvars; ++b )
14271  {
14272  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14273  {
14274  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14275  }
14276  }
14277 
14278 #if 0
14279  vbdvars = SCIPvarGetVubVars(var);
14280  nvbdvars = SCIPvarGetNVubs(var);
14281 
14282  for( b = 0; b < nvbdvars; ++b )
14283  {
14284  if( SCIPhashtableExists(vars, vbdvars[b]) )
14285  {
14286  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14287  }
14288  }
14289 #endif
14290  }
14291 
14292  /* create closing of the GML format */
14293  SCIPgmlWriteClosing(file);
14294 TERMINATE:
14295  /* close file */
14296  fclose(file);
14297 
14298  SCIPhashtableFree(&vars);
14299 
14300  return retcode;
14301 }
14302 
14303 /** sets method to solve an individual cumulative condition */
14305  SCIP* scip, /**< SCIP data structure */
14306  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14307  )
14308 {
14309  SCIP_CONSHDLR* conshdlr;
14310  SCIP_CONSHDLRDATA* conshdlrdata;
14311 
14312  /* find the cumulative constraint handler */
14313  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14314  if( conshdlr == NULL )
14315  {
14316  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14317  return SCIP_PLUGINNOTFOUND;
14318  }
14319 
14320  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14321  assert(conshdlrdata != NULL);
14322 
14323  conshdlrdata->solveCumulative = solveCumulative;
14324 
14325  return SCIP_OKAY;
14326 }
14327 
14328 /** solves given cumulative condition as independent sub problem
14329  *
14330  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14331  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14332  * solver was interrupted.
14333  */
14335  SCIP* scip, /**< SCIP data structure */
14336  int njobs, /**< number of jobs (activities) */
14337  SCIP_Real* ests, /**< array with the earlier start time for each job */
14338  SCIP_Real* lsts, /**< array with the latest start time for each job */
14339  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14340  int* durations, /**< array of durations */
14341  int* demands, /**< array of demands */
14342  int capacity, /**< cumulative capacity */
14343  int hmin, /**< left bound of time axis to be considered (including hmin) */
14344  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14345  SCIP_Real timelimit, /**< time limit for solving in seconds */
14346  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14347  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14348  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14349  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14350  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14351  SCIP_Bool* error /**< pointer to store if an error occurred */
14352  )
14353 {
14354  SCIP_CONSHDLR* conshdlr;
14355  SCIP_CONSHDLRDATA* conshdlrdata;
14356 
14357  (*solved) = TRUE;
14358  (*infeasible) = FALSE;
14359  (*unbounded) = FALSE;
14360  (*error) = FALSE;
14361 
14362  if( njobs == 0 )
14363  return SCIP_OKAY;
14364 
14365  /* find the cumulative constraint handler */
14366  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14367  if( conshdlr == NULL )
14368  {
14369  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14370  (*error) = TRUE;
14371  return SCIP_PLUGINNOTFOUND;
14372  }
14373 
14374  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14375  assert(conshdlrdata != NULL);
14376 
14377  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14378  if( timelimit > 0.0 && memorylimit > 10 )
14379  {
14380  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14381  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14382  }
14383 
14384  return SCIP_OKAY;
14385 }
14386 
14387 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14388  * completion time
14389  */
14391  SCIP* scip, /**< SCIP data structure */
14392  SCIP_PROFILE* profile, /**< resource profile */
14393  int nvars, /**< number of variables (jobs) */
14394  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14395  int* durations, /**< array containing corresponding durations */
14396  int* demands /**< array containing corresponding demands */
14397  )
14398 {
14399  SCIP_VAR* var;
14400  SCIP_HASHMAP* addedvars;
14401  int* copydemands;
14402  int* perm;
14403  int duration;
14404  int impliedest;
14405  int est;
14406  int impliedlct;
14407  int lct;
14408  int v;
14409 
14410  /* create hash map for variables which are added, mapping to their duration */
14411  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14412 
14413  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14414  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14415 
14416  /* sort variables w.r.t. job demands */
14417  for( v = 0; v < nvars; ++v )
14418  {
14419  copydemands[v] = demands[v];
14420  perm[v] = v;
14421  }
14422  SCIPsortDownIntInt(copydemands, perm, nvars);
14423 
14424  /* add each job with its earliest start and latest completion time into the resource profile */
14425  for( v = 0; v < nvars; ++v )
14426  {
14427  int idx;
14428 
14429  idx = perm[v];
14430  assert(idx >= 0 && idx < nvars);
14431 
14432  var = vars[idx];
14433  assert(var != NULL);
14434 
14435  duration = durations[idx];
14436  assert(duration > 0);
14437 
14438  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14439  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14440 
14441  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14442  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14443 
14444  if( impliedest < impliedlct )
14445  {
14446  SCIP_Bool infeasible;
14447  int pos;
14448 
14449  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14450  assert(!infeasible);
14451  assert(pos == -1);
14452  }
14453 
14454  if( est == impliedest && lct == impliedlct )
14455  {
14456  SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14457  }
14458  }
14459 
14460  SCIPfreeBufferArray(scip, &copydemands);
14461  SCIPfreeBufferArray(scip, &perm);
14462 
14463  SCIPhashmapFree(&addedvars);
14464 
14465  return SCIP_OKAY;
14466 }
14467 
14468 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14469 int SCIPcomputeHmin(
14470  SCIP* scip, /**< SCIP data structure */
14471  SCIP_PROFILE* profile, /**< worst case resource profile */
14472  int capacity /**< capacity to check */
14473  )
14474 {
14475  int* timepoints;
14476  int* loads;
14477  int ntimepoints;
14478  int t;
14479 
14480  ntimepoints = SCIPprofileGetNTimepoints(profile);
14481  timepoints = SCIPprofileGetTimepoints(profile);
14482  loads = SCIPprofileGetLoads(profile);
14483 
14484  /* find first time point which potentially violates the capacity restriction */
14485  for( t = 0; t < ntimepoints - 1; ++t )
14486  {
14487  /* check if the time point exceed w.r.t. worst case profile the capacity */
14488  if( loads[t] > capacity )
14489  {
14490  assert(t == 0 || loads[t-1] <= capacity);
14491  return timepoints[t];
14492  }
14493  }
14494 
14495  return INT_MAX;
14496 }
14497 
14498 /** 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}*/
14499 int SCIPcomputeHmax(
14500  SCIP* scip, /**< SCIP data structure */
14501  SCIP_PROFILE* profile, /**< worst case profile */
14502  int capacity /**< capacity to check */
14503  )
14504 {
14505  int* timepoints;
14506  int* loads;
14507  int ntimepoints;
14508  int t;
14509 
14510  ntimepoints = SCIPprofileGetNTimepoints(profile);
14511  timepoints = SCIPprofileGetTimepoints(profile);
14512  loads = SCIPprofileGetLoads(profile);
14513 
14514  /* find last time point which potentially violates the capacity restriction */
14515  for( t = ntimepoints - 1; t >= 0; --t )
14516  {
14517  /* check if at time point t the worst case resource profile exceeds the capacity */
14518  if( loads[t] > capacity )
14519  {
14520  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14521  return timepoints[t+1];
14522  }
14523  }
14524 
14525  return INT_MIN;
14526 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:8587
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4214
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3192
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1422
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8651
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:572
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18133
static SCIP_DECL_CONSCOPY(consCopyCumulative)
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:68
static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
#define DEFAULT_TTINFER
#define CONSHDLR_PROPFREQ
static int computeEnergyContribution(SCIP_BTNODE *node)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5209
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2134
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3298
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9385
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:365
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8353
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:595
static SCIP_RETCODE checkCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
constraint handler for cumulative constraints
static SCIP_RETCODE propagateEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:6961
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1998
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8696
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1091
void SCIPsortInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2496
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:49
static INFERINFO intToInferInfo(int i)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:886
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18111
static void consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file)
static SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
static SCIP_RETCODE analyzeConflictOverload(SCIP *scip, SCIP_BTNODE **leaves, int capacity, int nleaves, int est, int lct, int reportedenergy, SCIP_Bool propest, int shift, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
static SCIP_RETCODE createCoverCutsTimepoint(SCIP *scip, SCIP_CONS *cons, int *startvalues, int time)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17919
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:825
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:302
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3356
#define DEFAULT_MAXNODES
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:17461
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:638
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:317
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1758
static int computeOverlap(int begin, int end, int est, int lst, int duration)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2851
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static void normalizeCumulativeCondition(SCIP *scip, int nvars, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
static long bound
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1695
static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
#define CONSHDLR_NAME
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17975
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:435
#define CONSHDLR_PROP_TIMING
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
#define CONSHDLR_CHECKPRIORITY
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:104
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:496
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1470
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
static SCIP_RETCODE presolveConsEst(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6758
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1254
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:486
static SCIP_Longint computeCoreWithInterval(int begin, int end, int ect, int lst)
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:698
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip_cons.c:1571
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10300
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:8857
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
#define FALSE
Definition: def.h:96
static SCIP_RETCODE collectIntVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***activevars, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, int *lhs)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3023
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:324
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:111
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11072
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:175
SCIP_Real SCIPinfinity(SCIP *scip)
static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10764
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:95
#define SCIPdebug(x)
Definition: pub_message.h:93
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8373
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18153
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:54
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3141
static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17609
static SCIP_RETCODE applyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_Real leftub, SCIP_Real rightlb, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, SCIP_Bool *success, SCIP_Bool *cutoff)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:194
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8403
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
#define DEFAULT_LOCALCUTS
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5326
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:6931
#define SCIPdebugMessage
Definition: pub_message.h:96
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:229
#define CONSHDLR_DELAYPROP
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18123
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define DEFAULT_USEBINVARS
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
tclique user interface
static SCIP_RETCODE createCoreProfile(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3210
#define DEFAULT_COEFTIGHTENING
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:6667
static void normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
#define SCIP_LONGINT_MAX
Definition: def.h:172
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:292
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17471
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:575
#define DEFAULT_TTEFCHECK
static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
static SCIP_DECL_CONSINITLP(consInitlpCumulative)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:603
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8363
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:618
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6770
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1486
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:802
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8155
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:943
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:180
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:52
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8756
SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
static SCIP_RETCODE respropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, INFERINFO inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
static SCIP_RETCODE createConsCumulative(SCIP *scip, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
enum Proprule PROPRULE
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_Bool isConsIndependently(SCIP_CONS *cons)
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2245
static SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
static SCIP_RETCODE coretimesUpdateUb(SCIP *scip, SCIP_VAR *var, int duration, int demand, int capacity, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds)
static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_DESC
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17515
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3372
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4265
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1242
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_DECL_CONSCHECK(consCheckCumulative)
static SCIP_Longint computeTotalEnergy(int *durations, int *demands, int njobs)
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17929
static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, SCIP_Longint energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR **vars, SCIP_CONS **linkingconss, int *durations, int *demands, int nvars, int capacity, int hmin, int hmax, SCIP_Bool check)
Constraint handler for knapsack constraints of the form , x binary and .
static const NodeData nodedata[]
Definition: gastrans.c:83
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_PRESOLTIMING
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:53
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2622
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:341
static SCIP_RETCODE collectBranchingCands(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nbranchcands)
#define CONSHDLR_DELAYSEPA
static SCIP_RETCODE findCumulativeConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static int inferInfoGetData2(INFERINFO inferinfo)
#define EVENTHDLR_NAME
static SCIP_RETCODE propagateTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSLOCK(consLockCumulative)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:8706
SCIP_Real * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
#define SCIPerrorMessage
Definition: pub_message.h:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4184
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2778
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
SCIP_RETCODE SCIPcheckCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3482
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8843
static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
SCIP_RETCODE SCIPcreateConsCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:122
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1800
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *linkvar, SCIP_VAR **binvars, SCIP_Real *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:429
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:483
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:10895
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4443
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8094
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18185
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8721
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8313
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17260
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:366
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3057
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4204
static SCIP_RETCODE propagateCumulativeCondition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *redundant, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
#define NULL
Definition: lpi_spx1.cpp:164
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
static SCIP_RETCODE coretimesUpdateLb(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *infeasible)
static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
static SCIP_RETCODE solveCumulative(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool local, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
#define SCIP_CALL(x)
Definition: def.h:393
enum Proprule PROPRULE
Definition: cons_and.c:178
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:61
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18143
static SCIP_RETCODE propagateLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *ects, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void updateEnvelope(SCIP *scip, SCIP_BTNODE *node)
void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
#define SCIPstatisticPrintf
Definition: pub_message.h:126
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip_param.c:861
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6666
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18175
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8333
#define DEFAULT_PRESOLPAIRWISE
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1084
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_DETECTDISJUNCTIVE
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:641
static SCIP_DECL_CONSFREE(consFreeCumulative)
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8794
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:123
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:8979
static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
constraint handler for linking binary variables to a linking (continuous or integer) variable ...
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8726
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIP_UNKNOWN
Definition: def.h:207
static SCIP_RETCODE propagateUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *lsts, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
#define SCIP_Bool
Definition: def.h:93
static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
static SCIP_DECL_CONSPROP(consPropCumulative)
#define DEFAULT_DUALPRESOLVE
static SCIP_RETCODE analyseInfeasibelCoreInsertion(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferduration, int inferdemand, int inferpeak, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
#define DEFAULT_USEADJUSTEDJOBS
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
void SCIPprintSysError(const char *message)
Definition: misc.c:10673
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:670
#define DEFAULT_USECOVERCUTS
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6784
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2482
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:179
#define MAX(x, y)
Definition: tclique_def.h:92
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10865
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8114
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11950
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8887
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8223
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8776
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8293
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8263
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17767
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:114
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:665
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:58
static SCIP_Bool inferInfoIsValid(INFERINFO inferinfo)
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8282
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:136
int SCIPgetNRuns(SCIP *scip)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4357
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6696
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:779
static SCIP_RETCODE inferboundsEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_BT *tree, SCIP_BTNODE **leaves, int capacity, int ncands, SCIP_Bool propest, int shift, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
#define CONSHDLR_NEEDSCONS
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6738
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5507
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_DECL_SORTINDCOMP(compNodedataLct)
#define DEFAULT_FILLBRANCHCANDS
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6748
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip_param.c:661
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2295
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:8969
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2000
#define DEFAULT_DETECTVARBOUNDS
static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, SCIP_Longint energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8716
static SCIP_RETCODE setupAndSolveCumulativeSubscip(SCIP *subscip, SCIP_Real *objvals, int *durations, int *demands, int njobs, int capacity, int hmin, int hmax, SCIP_Longint maxnodes, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *solved, SCIP_Bool *error)
SCIP_Real * r
Definition: circlepacking.c:59
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:510
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPrespropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool *explanation, SCIP_RESULT *result)
SCIP_VAR ** b
Definition: circlepacking.c:65
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:8992
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3388
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
#define CONSHDLR_SEPAFREQ
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8829
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5449
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2313
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip_mem.c:100
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:711
static SCIP_DECL_CONSPRINT(consPrintCumulative)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1676
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8124
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5621
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3606
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1267
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3050
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1119
#define DEFAULT_CUTSASCONSS
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static void collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:534
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:273
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2004
static SCIP_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip_mem.c:126
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1955
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17379
#define SCIPstatistic(x)
Definition: pub_message.h:120
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip_var.c:8407
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
#define SCIP_Real
Definition: def.h:186
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8343
static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
static SCIP_DECL_CONSPARSE(consParseCumulative)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:703
static SCIP_DECL_CONSTRANS(consTransCumulative)
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:848
static SCIP_RETCODE propagateTimetable(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:414
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
#define DEFAULT_EFCHECK
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8283
#define SCIP_INVALID
Definition: def.h:206
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA *nodedatas, int *nodedataidx, int *nnodedatas)
#define EVENTHDLR_DESC
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8273
Proprule
Definition: cons_and.c:170
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2206
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18165
#define DEFAULT_TTEFINFER
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
#define SCIP_Longint
Definition: def.h:171
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17599
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2161
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17425
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2608
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
#define nnodes
Definition: gastrans.c:74
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17985
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:682
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17402
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:132
#define DEFAULT_USEBDWIDENING
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:9254
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:10274
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8868
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3230
static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
int TCLIQUE_WEIGHT
Definition: tclique.h:48
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6728
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:462
#define SCIPABORT()
Definition: def.h:365
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9031
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1361
default SCIP plugins
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8635
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip_param.c:883
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8766
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:545
static int inferInfoToInt(INFERINFO inferinfo)
static void computeCoreEnergyAfter(SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
SCIP_RETCODE SCIPpresolveCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17589
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6680
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:324
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:275
#define DEFAULT_SEPAOLD
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1217