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 (C) 2002-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_cumulative.c
17  * @brief constraint handler for cumulative constraints
18  * @author Timo Berthold
19  * @author Stefan Heinz
20  * @author Jens Schulz
21  *
22  * Given:
23  * - 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
24  * their demands \f$d_j\f$.
25  * - an integer resource capacity \f$C\f$
26  *
27  * 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.
28  *
29  * Separation:
30  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
31  * - or by just separating relatively weak cuts on the integer start time variables
32  *
33  * Propagation:
34  * - time tabling, Klein & Scholl (1999)
35  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
36  * (2009)
37  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
38  *
39  */
40 
41 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 
43 #include <assert.h>
44 #include <string.h>
45 
46 #include "tclique/tclique.h"
47 #include "scip/cons_cumulative.h"
48 #include "scip/cons_linking.h"
49 #include "scip/cons_knapsack.h"
50 #include "scip/scipdefplugins.h"
51 
52 /**@name Constraint handler properties
53  *
54  * @{
55  */
56 
57 /* constraint handler properties */
58 #define CONSHDLR_NAME "cumulative"
59 #define CONSHDLR_DESC "cumulative constraint handler"
60 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
61 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
62 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
63 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
64 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
65 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
66  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
67 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
68 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
69 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
70 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
71 
72 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
73 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
74 
75 /**@} */
76 
77 /**@name Default parameter values
78  *
79  * @{
80  */
81 
82 /* default parameter values */
83 
84 /* separation */
85 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
86 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
87 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
88 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
89 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
90 
91 /* propagation */
92 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
93 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
94 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
95 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
96 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
97 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
98 
99 /* presolving */
100 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
101 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
102 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
103 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
104 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
105 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
106 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
107 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
109 /* enforcement */
110 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
112 /* conflict analysis */
113 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
115 /**@} */
116 
117 /**@name Event handler properties
118  *
119  * @{
120  */
121 
122 #define EVENTHDLR_NAME "cumulative"
123 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
125 /**@} */
126 
127 /*
128  * Data structures
129  */
130 
131 /** constraint data for cumulative constraints */
132 struct SCIP_ConsData
133 {
134  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
135  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
136  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
137  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
138  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
139  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
140  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
141  int* demands; /**< array containing corresponding demands */
142  int* durations; /**< array containing corresponding durations */
143  SCIP_Real resstrength1; /**< stores the resource strength 1*/
144  SCIP_Real resstrength2; /**< stores the resource strength 2 */
145  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
146  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
147  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
148  SCIP_Real estimatedstrength;
149  int nvars; /**< number of variables */
150  int varssize; /**< size of the arrays */
151  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
152  int demandrowssize; /**< size of array rows of demand rows */
153  int nscoverrows; /**< number of rows of small cover cuts */
154  int scoverrowssize; /**< size of array of small cover cuts */
155  int nbcoverrows; /**< number of rows of big cover cuts */
156  int bcoverrowssize; /**< size of array of big cover cuts */
157  int capacity; /**< available cumulative capacity */
158 
159  int hmin; /**< left bound of time axis to be considered (including hmin) */
160  int hmax; /**< right bound of time axis to be considered (not including hmax) */
161 
162  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
163 
164  unsigned int validsignature:1; /**< is the signature valid */
165  unsigned int normalized:1; /**< is the constraint normalized */
166  unsigned int covercuts:1; /**< cover cuts are created? */
167  unsigned int propagated:1; /**< is constraint propagted */
168  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
169  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
170 
171 #ifdef SCIP_STATISTIC
172  int maxpeak;
173 #endif
174 };
175 
176 /** constraint handler data */
177 struct SCIP_ConshdlrData
178 {
179  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
180 
181  SCIP_Bool usebinvars; /**< should the binary variables be used? */
182  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
183  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
184  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
185  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
186  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
187  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
188  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
189  SCIP_Bool localcuts; /**< should cuts be added only locally? */
190  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
191  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
192 
193  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
194 
195  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
196  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
197  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
198  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
199  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
200  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
201  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
202  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
203  SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
204 
205  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
206 
207  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
208 
209  /* statistic values which are collected if SCIP_STATISTIC is defined */
210 #ifdef SCIP_STATISTIC
211  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
212  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
213  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
214  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
215  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
216  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
217  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
218  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
219  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
220  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
221 
222  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
223  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
224  int nremovedlocks; /**< number of times a up or down lock was removed */
225  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
226  int ndecomps; /**< number of times a constraint was decomposed */
227  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
228  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
229  int naddedvarbounds; /**< number of added variable bounds constraints */
230  int naddeddisjunctives; /**< number of added disjunctive constraints */
231 
232  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
233 #endif
234 };
235 
236 /**@name Inference Information Methods
237  *
238  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
239  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
240  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
241  *
242  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
243  * change and the earliest start and latest completion time of all jobs in the conflict set.
244  *
245  * @{
246  */
247 
248 /** Propagation rules */
249 enum Proprule
250 {
251  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
252  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
253  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
254 };
255 typedef enum Proprule PROPRULE;
257 /** inference information */
258 struct InferInfo
259 {
260  union
261  {
262  /** struct to use the inference information */
263  struct
264  {
265  unsigned int proprule:2; /**< propagation rule that was applied */
266  unsigned int data1:15; /**< data field one */
267  unsigned int data2:15; /**< data field two */
268  } asbits;
269  int asint; /**< inference information as a single int value */
270  } val;
271 };
272 typedef struct InferInfo INFERINFO;
274 /** converts an integer into an inference information */
275 static
276 INFERINFO intToInferInfo(
277  int i /**< integer to convert */
278  )
279 {
280  INFERINFO inferinfo;
281 
282  inferinfo.val.asint = i;
283 
284  return inferinfo;
285 }
286 
287 /** converts an inference information into an int */
288 static
289 int inferInfoToInt(
290  INFERINFO inferinfo /**< inference information to convert */
291  )
292 {
293  return inferinfo.val.asint;
294 }
295 
296 /** returns the propagation rule stored in the inference information */
297 static
299  INFERINFO inferinfo /**< inference information to convert */
300  )
301 {
302  return (PROPRULE) inferinfo.val.asbits.proprule;
303 }
304 
305 /** returns data field one of the inference information */
306 static
308  INFERINFO inferinfo /**< inference information to convert */
309  )
310 {
311  return (int) inferinfo.val.asbits.data1;
312 }
313 
314 /** returns data field two of the inference information */
315 static
317  INFERINFO inferinfo /**< inference information to convert */
318  )
319 {
320  return (int) inferinfo.val.asbits.data2;
321 }
322 
323 
324 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
325 static
326 INFERINFO getInferInfo(
327  PROPRULE proprule, /**< propagation rule that deduced the value */
328  int data1, /**< data field one */
329  int data2 /**< data field two */
330  )
331 {
332  INFERINFO inferinfo;
333 
334  /* check that the data menber are in the range of the available bits */
335  assert((int)proprule <= (1<<2)-1); /*lint !e685*/
336  assert(data1 >= 0 && data1 < (1<<15));
337  assert(data2 >= 0 && data2 < (1<<15));
338 
339  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
340  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
341  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
342 
343  return inferinfo;
344 }
345 
346 /**@} */
347 
348 /*
349  * Local methods
350  */
351 
352 /**@name Miscellaneous Methods
353  *
354  * @{
355  */
356 
357 #ifndef NDEBUG
358 
359 /** compute the core of a job which lies in certain interval [begin, end) */
360 static
362  int begin, /**< begin of the interval */
363  int end, /**< end of the interval */
364  int ect, /**< earliest completion time */
365  int lst /**< latest start time */
366  )
367 {
368  int core;
369 
370  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
371 
372  return core;
373 }
374 #else
375 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
376 #endif
377 
378 /** returns the implied earliest start time */
379 static
381  SCIP* scip, /**< SCIP data structure */
382  SCIP_VAR* var, /**< variable for which the implied est should be returned */
383  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
384  int* est /**< pointer to store the implied earliest start time */
385  )
386 { /*lint --e{715}*/
387 #if 0
388  SCIP_VAR** vbdvars;
389  SCIP_VAR* vbdvar;
390  SCIP_Real* vbdcoefs;
391  SCIP_Real* vbdconsts;
392  void* image;
393  int nvbdvars;
394  int v;
395 #endif
396 
397  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
398 
399 #if 0
400  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
401 
402  nvbdvars = SCIPvarGetNVlbs(var);
403  vbdvars = SCIPvarGetVlbVars(var);
404  vbdcoefs = SCIPvarGetVlbCoefs(var);
405  vbdconsts = SCIPvarGetVlbConstants(var);
406 
407  for( v = 0; v < nvbdvars; ++v )
408  {
409  vbdvar = vbdvars[v];
410  assert(vbdvar != NULL);
411 
412  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
413 
414  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
415  {
416  int duration;
417  int vbdconst;
418 
419  duration = (int)(size_t)image;
420  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
421 
422  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
424  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
425 
426  if( duration >= vbdconst )
427  {
428  int impliedest;
429 
430  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
431 
432  if( (*est) < impliedest )
433  {
434  (*est) = impliedest;
435 
436  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
437  }
438  }
439  }
440  }
441 #endif
442 
443  return SCIP_OKAY;
444 }
445 
446 /** returns the implied latest completion time */
447 static
449  SCIP* scip, /**< SCIP data structure */
450  SCIP_VAR* var, /**< variable for which the implied est should be returned */
451  int duration, /**< duration of the given job */
452  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
453  int* lct /**< pointer to store the implied latest completion time */
454  )
455 { /*lint --e{715}*/
456 #if 0
457  SCIP_VAR** vbdvars;
458  SCIP_VAR* vbdvar;
459  SCIP_Real* vbdcoefs;
460  SCIP_Real* vbdconsts;
461  int nvbdvars;
462  int v;
463 #endif
464 
465  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
466 
467 #if 0
468  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
469 
470  nvbdvars = SCIPvarGetNVubs(var);
471  vbdvars = SCIPvarGetVubVars(var);
472  vbdcoefs = SCIPvarGetVubCoefs(var);
473  vbdconsts = SCIPvarGetVubConstants(var);
474 
475  for( v = 0; v < nvbdvars; ++v )
476  {
477  vbdvar = vbdvars[v];
478  assert(vbdvar != NULL);
479 
480  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
481  {
482  int vbdconst;
483 
484  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
485 
486  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
488  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
489 
490  if( duration >= -vbdconst )
491  {
492  int impliedlct;
493 
494  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
495 
496  if( (*lct) > impliedlct )
497  {
498  (*lct) = impliedlct;
499 
500  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
501  }
502  }
503  }
504  }
505 #endif
506 
507  return SCIP_OKAY;
508 }
509 
510 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
511 static
513  SCIP* scip, /**< SCIP data structure */
514  SCIP_CONSDATA* consdata, /**< constraint data */
515  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
516  int** coefs, /**< pointer to store the coefficients */
517  int* nvars, /**< number if collect binary variables */
518  int* startindices, /**< permutation with rspect to the start times */
519  int curtime, /**< current point in time */
520  int nstarted, /**< number of jobs that start before the curtime or at curtime */
521  int nfinished /**< number of jobs that finished before curtime or at curtime */
522  )
523 {
524  int nrowvars;
525  int startindex;
526  int size;
527 
528  size = 10;
529  nrowvars = 0;
530  startindex = nstarted - 1;
531 
532  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
533  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
534 
535  /* search for the (nstarted - nfinished) jobs which are active at curtime */
536  while( nstarted - nfinished > nrowvars )
537  {
538  SCIP_VAR* var;
539  int endtime;
540  int duration;
541  int demand;
542  int varidx;
543 
544  /* collect job information */
545  varidx = startindices[startindex];
546  assert(varidx >= 0 && varidx < consdata->nvars);
547 
548  var = consdata->vars[varidx];
549  duration = consdata->durations[varidx];
550  demand = consdata->demands[varidx];
551  assert(var != NULL);
552 
553  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
554 
555  /* check the end time of this job is larger than the curtime; in this case the job is still running */
556  if( endtime > curtime )
557  {
558  SCIP_VAR** binvars;
559  int* vals;
560  int nbinvars;
561  int start;
562  int end;
563  int b;
564 
565  /* check if the linking constraints exists */
566  assert(SCIPexistsConsLinking(scip, var));
567  assert(SCIPgetConsLinking(scip, var) != NULL);
568  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
569 
570  /* collect linking constraint information */
571  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
572  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
573 
574  start = curtime - duration + 1;
575  end = MIN(curtime, endtime - duration);
576 
577  for( b = 0; b < nbinvars; ++b )
578  {
579  if( vals[b] < start )
580  continue;
581 
582  if( vals[b] > end )
583  break;
584 
585  assert(binvars[b] != NULL);
586 
587  /* ensure array proper array size */
588  if( size == *nvars )
589  {
590  size *= 2;
591  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
592  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
593  }
594 
595  (*vars)[*nvars] = binvars[b];
596  (*coefs)[*nvars] = demand;
597  (*nvars)++;
598  }
599  nrowvars++;
600  }
601 
602  startindex--;
603  }
604 
605  return SCIP_OKAY;
606 }
607 
608 /** collect all integer variable which belong to jobs which can run at the point of interest */
609 static
611  SCIP* scip, /**< SCIP data structure */
612  SCIP_CONSDATA* consdata, /**< constraint data */
613  SCIP_VAR*** activevars, /**< jobs that are currently running */
614  int* startindices, /**< permutation with rspect to the start times */
615  int curtime, /**< current point in time */
616  int nstarted, /**< number of jobs that start before the curtime or at curtime */
617  int nfinished, /**< number of jobs that finished before curtime or at curtime */
618  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
619  int* lhs /**< lhs for the new row sum of lbs + minoffset */
620  )
621 {
622  SCIP_VAR* var;
623  int startindex;
624  int endtime;
625  int duration;
626  int starttime;
627 
628  int varidx;
629  int sumofstarts;
630  int mindelta;
631  int counter;
632 
633  assert(curtime >= consdata->hmin);
634  assert(curtime < consdata->hmax);
635 
636  counter = 0;
637  sumofstarts = 0;
638 
639  mindelta = INT_MAX;
640 
641  startindex = nstarted - 1;
642 
643  /* search for the (nstarted - nfinished) jobs which are active at curtime */
644  while( nstarted - nfinished > counter )
645  {
646  assert(startindex >= 0);
647 
648  /* collect job information */
649  varidx = startindices[startindex];
650  assert(varidx >= 0 && varidx < consdata->nvars);
651 
652  var = consdata->vars[varidx];
653  duration = consdata->durations[varidx];
654  assert(duration > 0);
655  assert(var != NULL);
656 
657  if( lower )
658  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
659  else
660  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
661 
662  endtime = MIN(starttime + duration, consdata->hmax);
663 
664  /* check the end time of this job is larger than the curtime; in this case the job is still running */
665  if( endtime > curtime )
666  {
667  (*activevars)[counter] = var;
668  sumofstarts += starttime;
669  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
670  counter++;
671  }
672 
673  startindex--;
674  }
675 
676  assert(mindelta > 0);
677  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
678 
679  return SCIP_OKAY;
680 }
681 
682 /** initialize the sorted event point arrays */
683 static
685  SCIP* scip, /**< SCIP data structure */
686  int nvars, /**< number of start time variables (activities) */
687  SCIP_VAR** vars, /**< array of start time variables */
688  int* durations, /**< array of durations per start time variable */
689  int* starttimes, /**< array to store sorted start events */
690  int* endtimes, /**< array to store sorted end events */
691  int* startindices, /**< permutation with rspect to the start times */
692  int* endindices, /**< permutation with rspect to the end times */
693  SCIP_Bool local /**< shall local bounds be used */
694  )
695 {
696  SCIP_VAR* var;
697  int j;
698 
699  assert(vars != NULL || nvars == 0);
700 
701  /* assign variables, start and endpoints to arrays */
702  for ( j = 0; j < nvars; ++j )
703  {
704  assert(vars != NULL);
705 
706  var = vars[j];
707  assert(var != NULL);
708 
709  if( local )
710  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
711  else
712  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
713 
714  startindices[j] = j;
715 
716  if( local )
717  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
718  else
719  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
720 
721  endindices[j] = j;
722  }
723 
724  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
725  SCIPsortIntInt(starttimes, startindices, j);
726  SCIPsortIntInt(endtimes, endindices, j);
727 }
728 
729 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
730 static
732  SCIP* scip, /**< SCIP data structure */
733  SCIP_SOL* sol, /**< solution */
734  int nvars, /**< number of start time variables (activities) */
735  SCIP_VAR** vars, /**< array of start time variables */
736  int* durations, /**< array of durations per start time variable */
737  int* starttimes, /**< array to store sorted start events */
738  int* endtimes, /**< array to store sorted end events */
739  int* startindices, /**< permutation with rspect to the start times */
740  int* endindices /**< permutation with rspect to the end times */
741  )
742 {
743  SCIP_VAR* var;
744  int j;
745 
746  assert(vars != NULL || nvars == 0);
747 
748  /* assign variables, start and endpoints to arrays */
749  for ( j = 0; j < nvars; ++j )
750  {
751  assert(vars != NULL);
752 
753  var = vars[j];
754  assert(var != NULL);
755 
756  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
757  startindices[j] = j;
758 
759  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
760  endindices[j] = j;
761  }
762 
763  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
764  SCIPsortIntInt(starttimes, startindices, j);
765  SCIPsortIntInt(endtimes, endindices, j);
766 }
767 
768 /** initialize the sorted event point arrays
769  *
770  * @todo Check the separation process!
771  */
772 static
774  SCIP* scip, /**< SCIP data structure */
775  SCIP_CONSDATA* consdata, /**< constraint data */
776  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
777  int* starttimes, /**< array to store sorted start events */
778  int* endtimes, /**< array to store sorted end events */
779  int* startindices, /**< permutation with rspect to the start times */
780  int* endindices, /**< permutation with rspect to the end times */
781  int* nvars, /**< number of variables that are integral */
782  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
783  )
784 {
785  SCIP_VAR* var;
786  int tmpnvars;
787  int j;
788 
789  tmpnvars = consdata->nvars;
790  *nvars = 0;
791 
792  /* assign variables, start and endpoints to arrays */
793  for ( j = 0; j < tmpnvars; ++j )
794  {
795  var = consdata->vars[j];
796  assert(var != NULL);
797  assert(consdata->durations[j] > 0);
798  assert(consdata->demands[j] > 0);
799 
800  if( lower )
801  {
802  /* only consider jobs that are at their lower or upper bound */
803  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
804  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
805  continue;
806 
807  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
808  startindices[*nvars] = j;
809 
810  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
811  endindices[*nvars] = j;
812 
813  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
814  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
815  consdata->durations[j],
816  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
817  consdata->demands[startindices[*nvars]]);
818 
819  (*nvars)++;
820  }
821  else
822  {
823  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
824  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
825  continue;
826 
827  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
828  startindices[*nvars] = j;
829 
830  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
831  endindices[*nvars] = j;
832 
833  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
834  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
835  consdata->durations[j],
836  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
837  consdata->demands[startindices[*nvars]]);
838 
839  (*nvars)++;
840  }
841  }
842 
843  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
844  SCIPsortIntInt(starttimes, startindices, *nvars);
845  SCIPsortIntInt(endtimes, endindices, *nvars);
846 
847 #ifdef SCIP_DEBUG
848  SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
849 
850  for ( j = 0; j < *nvars; ++j )
851  {
852  SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
853  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
854  consdata->demands[startindices[j]]);
855  }
856 
857  for ( j = 0; j < *nvars; ++j )
858  {
859  SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
860  consdata->demands[endindices[j]]);
861  }
862 #endif
863 }
864 
865 #ifdef SCIP_STATISTIC
866 /** this method checks for relevant intervals for energetic reasoning */
867 static
868 SCIP_RETCODE computeRelevantEnergyIntervals(
869  SCIP* scip, /**< SCIP data structure */
870  int nvars, /**< number of start time variables (activities) */
871  SCIP_VAR** vars, /**< array of start time variables */
872  int* durations, /**< array of durations */
873  int* demands, /**< array of demands */
874  int capacity, /**< cumulative capacity */
875  int hmin, /**< left bound of time axis to be considered (including hmin) */
876  int hmax, /**< right bound of time axis to be considered (not including hmax) */
877  int** timepoints, /**< array to store relevant points in time */
878  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
879  int* ntimepoints, /**< pointer to store the number of timepoints */
880  int* maxdemand, /**< pointer to store maximum over all demands */
881  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
882  )
883 {
884  int* starttimes; /* stores when each job is starting */
885  int* endtimes; /* stores when each job ends */
886  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
887  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
888 
889  SCIP_Real totaldemand;
890  int curtime; /* point in time which we are just checking */
891  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
892 
893  int j;
894 
895  assert( scip != NULL );
896  assert(durations != NULL);
897  assert(demands != NULL);
898  assert(capacity >= 0);
899 
900  /* if no activities are associated with this cumulative then this constraint is redundant */
901  if( nvars == 0 )
902  return SCIP_OKAY;
903 
904  assert(vars != NULL);
905 
906  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
907  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
908  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
909  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
910 
911  /* create event point arrays */
912  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
913 
914  endindex = 0;
915  totaldemand = 0.0;
916 
917  *ntimepoints = 0;
918  (*timepoints)[0] = starttimes[0];
919  (*cumulativedemands)[0] = 0;
920  *maxdemand = 0;
921 
922  /* check each startpoint of a job whether the capacity is kept or not */
923  for( j = 0; j < nvars; ++j )
924  {
925  int lct;
926  int idx;
927 
928  curtime = starttimes[j];
929 
930  if( curtime >= hmax )
931  break;
932 
933  /* free all capacity usages of jobs the are no longer running */
934  while( endindex < nvars && endtimes[endindex] <= curtime )
935  {
936  int est;
937 
938  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
939  {
940  (*ntimepoints)++;
941  (*timepoints)[*ntimepoints] = endtimes[endindex];
942  (*cumulativedemands)[*ntimepoints] = 0;
943  }
944 
945  idx = endindices[endindex];
946  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
947  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
948  endindex++;
949 
950  (*cumulativedemands)[*ntimepoints] = totaldemand;
951  }
952 
953  idx = startindices[j];
954  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
955  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
956 
957  if( (*timepoints)[*ntimepoints] < curtime )
958  {
959  (*ntimepoints)++;
960  (*timepoints)[*ntimepoints] = curtime;
961  (*cumulativedemands)[*ntimepoints] = 0;
962  }
963 
964  (*cumulativedemands)[*ntimepoints] = totaldemand;
965 
966  /* add the relative capacity requirements for all job which start at the curtime */
967  while( j+1 < nvars && starttimes[j+1] == curtime )
968  {
969  ++j;
970  idx = startindices[j];
971  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
972  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
973 
974  (*cumulativedemands)[*ntimepoints] = totaldemand;
975  }
976  } /*lint --e{850}*/
977 
978  /* free all capacity usages of jobs that are no longer running */
979  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
980  {
981  int est;
982  int idx;
983 
984  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
985  {
986  (*ntimepoints)++;
987  (*timepoints)[*ntimepoints] = endtimes[endindex];
988  (*cumulativedemands)[*ntimepoints] = 0;
989  }
990 
991  idx = endindices[endindex];
992  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
993  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
994  (*cumulativedemands)[*ntimepoints] = totaldemand;
995 
996  ++endindex;
997  }
998 
999  (*ntimepoints)++;
1000  /* compute minimum free capacity */
1001  (*minfreecapacity) = INT_MAX;
1002  for( j = 0; j < *ntimepoints; ++j )
1003  {
1004  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1005  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1006  }
1007 
1008  /* free buffer arrays */
1009  SCIPfreeBufferArray(scip, &endindices);
1010  SCIPfreeBufferArray(scip, &startindices);
1011  SCIPfreeBufferArray(scip, &endtimes);
1012  SCIPfreeBufferArray(scip, &starttimes);
1013 
1014  return SCIP_OKAY;
1015 }
1016 
1017 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1018 static
1019 SCIP_RETCODE evaluateCumulativeness(
1020  SCIP* scip, /**< pointer to scip */
1021  SCIP_CONS* cons /**< cumulative constraint */
1022  )
1023 {
1024  SCIP_CONSDATA* consdata;
1025  int nvars;
1026  int v;
1027  int capacity;
1028 
1029  /* output values: */
1030  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1031  SCIP_Real cumfactor1;
1032  SCIP_Real resstrength1; /* overall strength */
1033  SCIP_Real resstrength2; /* timepoint wise maximum */
1034 
1035  /* helpful variables: */
1036  SCIP_Real globalpeak;
1037  SCIP_Real globalmaxdemand;
1038 
1039  /* get constraint data structure */
1040  consdata = SCIPconsGetData(cons);
1041  assert(consdata != NULL);
1042 
1043  nvars = consdata->nvars;
1044  capacity = consdata->capacity;
1045  globalpeak = 0.0;
1046  globalmaxdemand = 0.0;
1047 
1048  disjfactor2 = 0.0;
1049  cumfactor1 = 0.0;
1050  resstrength2 = 0.0;
1051 
1052  /* check each starting time (==each job, but inefficient) */
1053  for( v = 0; v < nvars; ++v )
1054  {
1055  SCIP_Real peak;
1056  SCIP_Real maxdemand;
1057  SCIP_Real deltademand;
1058  int ndemands;
1059  int nlarge;
1060 
1061  int timepoint;
1062  int j;
1063  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1064  peak = consdata->demands[v];
1065  ndemands = 1;
1066  maxdemand = 0;
1067  nlarge = 0;
1068 
1069  if( consdata->demands[v] > capacity / 3 )
1070  nlarge++;
1071 
1072  for( j = 0; j < nvars; ++j )
1073  {
1074  int lb;
1075 
1076  if( j == v )
1077  continue;
1078 
1079  maxdemand = 0.0;
1080  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1081 
1082  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1083  {
1084  peak += consdata->demands[j];
1085  ndemands++;
1086 
1087  if( consdata->demands[j] > consdata->capacity / 3 )
1088  nlarge++;
1089  }
1090  }
1091 
1092  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1093  globalpeak = MAX(globalpeak, peak);
1094  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1095 
1096  if( peak > capacity )
1097  {
1098  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1099  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1100  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1101  }
1102  }
1103 
1104  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1105 
1106  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1107  consdata->disjfactor2 = disjfactor2;
1108  consdata->cumfactor1 = cumfactor1;
1109  consdata->resstrength2 = resstrength2;
1110  consdata->resstrength1 = resstrength1;
1111 
1112  /* get estimated res strength */
1113  {
1114  int* timepoints;
1115  SCIP_Real* estimateddemands;
1116  int ntimepoints;
1117  int maxdemand;
1118  SCIP_Real minfreecapacity;
1119 
1120  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1121  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1122 
1123  ntimepoints = 0;
1124  minfreecapacity = INT_MAX;
1125 
1126  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1127  consdata->durations, consdata->demands,
1128  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1129  &ntimepoints, &maxdemand, &minfreecapacity) );
1130 
1131  /* free buffer arrays */
1132  SCIPfreeBufferArray(scip, &estimateddemands);
1133  SCIPfreeBufferArray(scip, &timepoints);
1134 
1135  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1136  }
1137 
1138  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1139  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1140  consdata->estimatedstrength);
1141 
1142  return SCIP_OKAY;
1143 }
1144 #endif
1145 
1146 /** gets the active variables together with the constant */
1147 static
1149  SCIP* scip, /**< SCIP data structure */
1150  SCIP_VAR** var, /**< pointer to store the active variable */
1151  int* scalar, /**< pointer to store the scalar */
1152  int* constant /**< pointer to store the constant */
1153  )
1154 {
1155  if( !SCIPvarIsActive(*var) )
1156  {
1157  SCIP_Real realscalar;
1158  SCIP_Real realconstant;
1159 
1160  realscalar = 1.0;
1161  realconstant = 0.0;
1162 
1164 
1165  /* transform variable to active variable */
1166  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1167  assert(!SCIPisZero(scip, realscalar));
1168  assert(SCIPvarIsActive(*var));
1169 
1170  if( realconstant < 0.0 )
1171  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1172  else
1173  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1174 
1175  if( realscalar < 0.0 )
1176  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1177  else
1178  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1179  }
1180  else
1181  {
1182  (*scalar) = 1;
1183  (*constant) = 0;
1184  }
1185 
1186  assert(*scalar != 0);
1187 
1188  return SCIP_OKAY;
1189 }
1190 
1191 /** computes the total energy of all jobs */
1192 static
1193 int computeTotalEnergy(
1194  int* durations, /**< array of job durations */
1195  int* demands, /**< array of job demands */
1196  int njobs /**< number of jobs */
1197  )
1198 {
1199  int energy;
1200  int j;
1201 
1202  energy = 0;
1203 
1204  for( j = 0; j < njobs; ++j )
1205  energy += durations[j] * demands[j];
1206 
1207  return energy;
1208 }
1209 
1210 /**@} */
1211 
1212 /**@name Default method to solve a cumulative condition
1213  *
1214  * @{
1215  */
1216 
1217 /** setup and solve subscip to solve single cumulative condition */
1218 static
1220  SCIP* subscip, /**< subscip data structure */
1221  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1222  int* durations, /**< array of durations */
1223  int* demands, /**< array of demands */
1224  int njobs, /**< number of jobs (activities) */
1225  int capacity, /**< cumulative capacity */
1226  int hmin, /**< left bound of time axis to be considered (including hmin) */
1227  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1228  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1229  SCIP_Real timelimit, /**< time limit for solving in seconds */
1230  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1231  SCIP_Real* ests, /**< array of earliest start times for each job */
1232  SCIP_Real* lsts, /**< array of latest start times for each job */
1233  SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1234  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1235  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1236  SCIP_Bool* error /**< pointer to store if an error occurred */
1237  )
1238 {
1239  SCIP_VAR** subvars;
1240  SCIP_CONS* cons;
1241 
1242  char name[SCIP_MAXSTRLEN];
1243  int v;
1244  SCIP_RETCODE retcode;
1245 
1246  assert(subscip != NULL);
1247 
1248  /* copy all plugins */
1250 
1251  /* create the subproblem */
1252  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1253 
1254  SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1255 
1256  /* create for each job a start time variable */
1257  for( v = 0; v < njobs; ++v )
1258  {
1259  SCIP_Real objval;
1260 
1261  /* construct variable name */
1262  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1263 
1264  if( objvals == NULL )
1265  objval = 0.0;
1266  else
1267  objval = objvals[v];
1268 
1269  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1270  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1271  }
1272 
1273  /* create cumulative constraint */
1274  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1275  njobs, subvars, durations, demands, capacity) );
1276 
1277  /* set effective horizon */
1278  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1279  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1280 
1281  /* add cumulative constraint */
1282  SCIP_CALL( SCIPaddCons(subscip, cons) );
1283  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1284 
1285  /* set CP solver settings
1286  *
1287  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1288  * time limit.
1289  */
1291 
1292  /* do not abort subproblem on CTRL-C */
1293  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1294 
1295  /* disable output to console */
1296  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1297 
1298  /* set limits for the subproblem */
1299  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1300  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1301  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1302 
1303  /* forbid recursive call of heuristics and separators solving subMIPs */
1304  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1305 
1306  /* solve single cumulative constraint by branch and bound */
1307  retcode = SCIPsolve(subscip);
1308 
1309  if( retcode != SCIP_OKAY )
1310  (*error) = TRUE;
1311  else
1312  {
1313  SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1314 
1315  /* evaluated solution status */
1316  switch( SCIPgetStatus(subscip) )
1317  {
1318  case SCIP_STATUS_INFORUNBD:
1320  (*infeasible) = TRUE;
1321  (*solved) = TRUE;
1322  break;
1323  case SCIP_STATUS_UNBOUNDED:
1324  (*unbounded) = TRUE;
1325  (*solved) = TRUE;
1326  break;
1327  case SCIP_STATUS_OPTIMAL:
1328  {
1329  SCIP_SOL* sol;
1330  SCIP_Real solval;
1331 
1332  sol = SCIPgetBestSol(subscip);
1333  assert(sol != NULL);
1334 
1335  for( v = 0; v < njobs; ++v )
1336  {
1337  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1338 
1339  ests[v] = solval;
1340  lsts[v] = solval;
1341  }
1342  (*solved) = TRUE;
1343  break;
1344  }
1345  case SCIP_STATUS_NODELIMIT:
1347  case SCIP_STATUS_TIMELIMIT:
1348  case SCIP_STATUS_MEMLIMIT:
1350  case SCIP_STATUS_TERMINATE:
1351  /* transfer the global bound changes */
1352  for( v = 0; v < njobs; ++v )
1353  {
1354  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1355  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1356  }
1357  (*solved) = FALSE;
1358  break;
1359 
1360  case SCIP_STATUS_UNKNOWN:
1362  case SCIP_STATUS_GAPLIMIT:
1363  case SCIP_STATUS_SOLLIMIT:
1366  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1367  return SCIP_INVALIDDATA;
1368  }
1369  }
1370 
1371  /* release all variables */
1372  for( v = 0; v < njobs; ++v )
1373  {
1374  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1375  }
1376 
1377  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1378 
1379  return SCIP_OKAY;
1380 }
1381 
1382 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1383 static
1384 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1386  SCIP* subscip;
1387 
1388  SCIP_RETCODE retcode;
1389 
1390  assert(njobs > 0);
1391 
1392  (*solved) = FALSE;
1393  (*infeasible) = FALSE;
1394  (*unbounded) = FALSE;
1395  (*error) = FALSE;
1396 
1397  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1398 
1399  /* initialize the sub-problem */
1400  SCIP_CALL( SCIPcreate(&subscip) );
1401 
1402  /* create and solve the subproblem. catch possible errors */
1403  retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1404  njobs, capacity, hmin, hmax,
1405  maxnodes, timelimit, memorylimit,
1406  ests, lsts,
1407  infeasible, unbounded, solved, error);
1408 
1409  /* free the subscip in any case */
1410  SCIP_CALL( SCIPfree(&subscip) );
1411 
1412  SCIP_CALL( retcode );
1413 
1414  return SCIP_OKAY;
1415 }
1416 
1417 #if 0
1418 /** solve single cumulative condition using SCIP and the time indexed formulation */
1419 static
1420 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1421 {
1422  SCIP* subscip;
1423  SCIP_VAR*** binvars;
1424  SCIP_RETCODE retcode;
1425  char name[SCIP_MAXSTRLEN];
1426  int minest;
1427  int maxlct;
1428  int t;
1429  int v;
1430 
1431  assert(njobs > 0);
1432 
1433  (*solved) = FALSE;
1434  (*infeasible) = FALSE;
1435  (*unbounded) = FALSE;
1436  (*error) = FALSE;
1437 
1438  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1439 
1440  /* initialize the sub-problem */
1441  SCIP_CALL( SCIPcreate(&subscip) );
1442 
1443  /* copy all plugins */
1445 
1446  /* create the subproblem */
1447  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1448 
1449  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1450 
1451  minest = INT_MAX;
1452  maxlct = INT_MIN;
1453 
1454  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1455  * partitioning constrain which forces that job starts
1456  */
1457  for( v = 0; v < njobs; ++v )
1458  {
1459  SCIP_CONS* cons;
1460  SCIP_Real objval;
1461  int timeinterval;
1462  int est;
1463  int lst;
1464 
1465  if( objvals == NULL )
1466  objval = 0.0;
1467  else
1468  objval = objvals[v];
1469 
1470  est = ests[v];
1471  lst = lsts[v];
1472 
1473  /* compute number of possible start points */
1474  timeinterval = lst - est + 1;
1475  assert(timeinterval > 0);
1476 
1477  /* compute the smallest earliest start time and largest latest completion time */
1478  minest = MIN(minest, est);
1479  maxlct = MAX(maxlct, lst + durations[v]);
1480 
1481  /* construct constraint name */
1482  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1483 
1484  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1485 
1486  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1487 
1488  for( t = 0; t < timeinterval; ++t )
1489  {
1490  SCIP_VAR* binvar;
1491 
1492  /* construct varibale name */
1493  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1494 
1495  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1496  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1497 
1498  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1499  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1500 
1501  binvars[v][t] = binvar;
1502  }
1503 
1504  /* add and release the set partitioning constraint */
1505  SCIP_CALL( SCIPaddCons(subscip, cons) );
1506  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1507  }
1508 
1509  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1510  hmin = MAX(hmin, minest);
1511  hmax = MIN(hmax, maxlct);
1512  assert(hmin > INT_MIN);
1513  assert(hmax < INT_MAX);
1514  assert(hmin < hmax);
1515 
1516  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1517  for( t = hmin; t < hmax; ++t )
1518  {
1519  SCIP_CONS* cons;
1520 
1521  /* construct constraint name */
1522  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1523 
1524  /* create an empty knapsack constraint */
1525  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1526 
1527  /* add all jobs which potentially can be processed at that time point */
1528  for( v = 0; v < njobs; ++v )
1529  {
1530  int duration;
1531  int demand;
1532  int start;
1533  int end;
1534  int est;
1535  int lst;
1536  int k;
1537 
1538  est = ests[v];
1539  lst = lsts[v] ;
1540 
1541  duration = durations[v];
1542  assert(duration > 0);
1543 
1544  /* check if the varibale is processed potentially at time point t */
1545  if( t < est || t >= lst + duration )
1546  continue;
1547 
1548  demand = demands[v];
1549  assert(demand >= 0);
1550 
1551  start = MAX(t - duration + 1, est);
1552  end = MIN(t, lst);
1553 
1554  assert(start <= end);
1555 
1556  for( k = start; k <= end; ++k )
1557  {
1558  assert(binvars[v][k] != NULL);
1559  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1560  }
1561  }
1562 
1563  /* add and release the knapsack constraint */
1564  SCIP_CALL( SCIPaddCons(subscip, cons) );
1565  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1566  }
1567 
1568  /* do not abort subproblem on CTRL-C */
1569  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1570 
1571  /* disable output to console */
1572  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1573 
1574  /* set limits for the subproblem */
1575  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1576  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1577  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1578 
1579  /* solve single cumulative constraint by branch and bound */
1580  retcode = SCIPsolve(subscip);
1581 
1582  if( retcode != SCIP_OKAY )
1583  (*error) = TRUE;
1584  else
1585  {
1586  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1587 
1588  /* evaluated solution status */
1589  switch( SCIPgetStatus(subscip) )
1590  {
1591  case SCIP_STATUS_INFORUNBD:
1593  (*infeasible) = TRUE;
1594  (*solved) = TRUE;
1595  break;
1596  case SCIP_STATUS_UNBOUNDED:
1597  (*unbounded) = TRUE;
1598  (*solved) = TRUE;
1599  break;
1600  case SCIP_STATUS_OPTIMAL:
1601  {
1602  SCIP_SOL* sol;
1603 
1604  sol = SCIPgetBestSol(subscip);
1605  assert(sol != NULL);
1606 
1607  for( v = 0; v < njobs; ++v )
1608  {
1609  int timeinterval;
1610  int est;
1611  int lst;
1612 
1613  est = ests[v];
1614  lst = lsts[v];
1615 
1616  /* compute number of possible start points */
1617  timeinterval = lst - est + 1;
1618 
1619  /* check which binary varibale is set to one */
1620  for( t = 0; t < timeinterval; ++t )
1621  {
1622  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1623  {
1624  ests[v] = est + t;
1625  lsts[v] = est + t;
1626  break;
1627  }
1628  }
1629  }
1630 
1631  (*solved) = TRUE;
1632  break;
1633  }
1634  case SCIP_STATUS_NODELIMIT:
1636  case SCIP_STATUS_TIMELIMIT:
1637  case SCIP_STATUS_MEMLIMIT:
1639  /* transfer the global bound changes */
1640  for( v = 0; v < njobs; ++v )
1641  {
1642  int timeinterval;
1643  int est;
1644  int lst;
1645 
1646  est = ests[v];
1647  lst = lsts[v];
1648 
1649  /* compute number of possible start points */
1650  timeinterval = lst - est + 1;
1651 
1652  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1653  for( t = 0; t < timeinterval; ++t )
1654  {
1655  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1656  {
1657  ests[v] = est + t;
1658  break;
1659  }
1660  }
1661 
1662  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1663  for( t = timeinterval - 1; t >= 0; --t )
1664  {
1665  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1666  {
1667  lsts[v] = est + t;
1668  break;
1669  }
1670  }
1671  }
1672  (*solved) = FALSE;
1673  break;
1674 
1675  case SCIP_STATUS_UNKNOWN:
1677  case SCIP_STATUS_GAPLIMIT:
1678  case SCIP_STATUS_SOLLIMIT:
1680  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1681  return SCIP_INVALIDDATA;
1682  }
1683  }
1684 
1685  /* release all variables */
1686  for( v = 0; v < njobs; ++v )
1687  {
1688  int timeinterval;
1689  int est;
1690  int lst;
1691 
1692  est = ests[v];
1693  lst = lsts[v];
1694 
1695  /* compute number of possible start points */
1696  timeinterval = lst - est + 1;
1697 
1698  for( t = 0; t < timeinterval; ++t )
1699  {
1700  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1701  }
1702  SCIPfreeBufferArray(subscip, &binvars[v]);
1703  }
1704 
1705  SCIPfreeBufferArray(subscip, &binvars);
1706 
1707  SCIP_CALL( SCIPfree(&subscip) );
1708 
1709  return SCIP_OKAY;
1710 }
1711 #endif
1712 
1713 /**@} */
1714 
1715 /**@name Constraint handler data
1716  *
1717  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1718  * handler.
1719  *
1720  * @{
1721  */
1722 
1723 /** creates constaint handler data for cumulative constraint handler */
1724 static
1726  SCIP* scip, /**< SCIP data structure */
1727  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1728  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1729  )
1730 {
1731  /* create precedence constraint handler data */
1732  assert(scip != NULL);
1733  assert(conshdlrdata != NULL);
1734  assert(eventhdlr != NULL);
1735 
1736  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1737 
1738  /* set event handler for checking if bounds of start time variables are tighten */
1739  (*conshdlrdata)->eventhdlr = eventhdlr;
1740 
1741  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1742  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1743 
1744 #ifdef SCIP_STATISTIC
1745  (*conshdlrdata)->nlbtimetable = 0;
1746  (*conshdlrdata)->nubtimetable = 0;
1747  (*conshdlrdata)->ncutofftimetable = 0;
1748  (*conshdlrdata)->nlbedgefinder = 0;
1749  (*conshdlrdata)->nubedgefinder = 0;
1750  (*conshdlrdata)->ncutoffedgefinder = 0;
1751  (*conshdlrdata)->ncutoffoverload = 0;
1752  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1753 
1754  (*conshdlrdata)->nirrelevantjobs = 0;
1755  (*conshdlrdata)->nalwaysruns = 0;
1756  (*conshdlrdata)->nremovedlocks = 0;
1757  (*conshdlrdata)->ndualfixs = 0;
1758  (*conshdlrdata)->ndecomps = 0;
1759  (*conshdlrdata)->ndualbranchs = 0;
1760  (*conshdlrdata)->nallconsdualfixs = 0;
1761  (*conshdlrdata)->naddedvarbounds = 0;
1762  (*conshdlrdata)->naddeddisjunctives = 0;
1763 #endif
1764 
1765  return SCIP_OKAY;
1766 }
1767 
1768 /** frees constraint handler data for logic or constraint handler */
1769 static
1770 void conshdlrdataFree(
1771  SCIP* scip, /**< SCIP data structure */
1772  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1773  )
1774 {
1775  assert(conshdlrdata != NULL);
1776  assert(*conshdlrdata != NULL);
1777 
1778  SCIPfreeBlockMemory(scip, conshdlrdata);
1779 }
1780 
1781 /**@} */
1782 
1783 
1784 /**@name Constraint data methods
1785  *
1786  * @{
1787  */
1788 
1789 /** catches bound change events for all variables in transformed cumulative constraint */
1790 static
1792  SCIP* scip, /**< SCIP data structure */
1793  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1794  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1795  )
1796 {
1797  int v;
1798 
1799  assert(scip != NULL);
1800  assert(consdata != NULL);
1801  assert(eventhdlr != NULL);
1802 
1803  /* catch event for every single variable */
1804  for( v = 0; v < consdata->nvars; ++v )
1805  {
1806  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1807  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1808  }
1809 
1810  return SCIP_OKAY;
1811 }
1812 
1813 /** drops events for variable at given position */
1814 static
1816  SCIP* scip, /**< SCIP data structure */
1817  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1818  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1819  int pos /**< array position of variable to catch bound change events for */
1820  )
1821 {
1822  assert(scip != NULL);
1823  assert(consdata != NULL);
1824  assert(eventhdlr != NULL);
1825  assert(0 <= pos && pos < consdata->nvars);
1826  assert(consdata->vars[pos] != NULL);
1827 
1828  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1829  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1830 
1831  return SCIP_OKAY;
1832 }
1833 
1834 /** drops bound change events for all variables in transformed linear constraint */
1835 static
1837  SCIP* scip, /**< SCIP data structure */
1838  SCIP_CONSDATA* consdata, /**< linear constraint data */
1839  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1840  )
1841 {
1842  int v;
1843 
1844  assert(scip != NULL);
1845  assert(consdata != NULL);
1846 
1847  /* drop event of every single variable */
1848  for( v = 0; v < consdata->nvars; ++v )
1849  {
1850  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1851  }
1852 
1853  return SCIP_OKAY;
1854 }
1855 
1856 /** initialize variable lock data structure */
1857 static
1858 void initializeLocks(
1859  SCIP_CONSDATA* consdata, /**< constraint data */
1860  SCIP_Bool locked /**< should the variable be locked? */
1861  )
1862 {
1863  int nvars;
1864  int v;
1865 
1866  nvars = consdata->nvars;
1867 
1868  /* initialize locking arrays */
1869  for( v = 0; v < nvars; ++v )
1870  {
1871  consdata->downlocks[v] = locked;
1872  consdata->uplocks[v] = locked;
1873  }
1874 }
1875 
1876 /** creates constraint data of cumulative constraint */
1877 static
1879  SCIP* scip, /**< SCIP data structure */
1880  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1881  SCIP_VAR** vars, /**< array of integer variables */
1882  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1883  int* durations, /**< array containing corresponding durations */
1884  int* demands, /**< array containing corresponding demands */
1885  int nvars, /**< number of variables */
1886  int capacity, /**< available cumulative capacity */
1887  int hmin, /**< left bound of time axis to be considered (including hmin) */
1888  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1889  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1890  )
1891 {
1892  int v;
1893 
1894  assert(scip != NULL);
1895  assert(consdata != NULL);
1896  assert(vars != NULL || nvars > 0);
1897  assert(demands != NULL);
1898  assert(durations != NULL);
1899  assert(capacity >= 0);
1900  assert(hmin >= 0);
1901  assert(hmin < hmax);
1902 
1903  /* create constraint data */
1904  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1905 
1906  (*consdata)->hmin = hmin;
1907  (*consdata)->hmax = hmax;
1908 
1909  (*consdata)->capacity = capacity;
1910  (*consdata)->demandrows = NULL;
1911  (*consdata)->demandrowssize = 0;
1912  (*consdata)->ndemandrows = 0;
1913  (*consdata)->scoverrows = NULL;
1914  (*consdata)->nscoverrows = 0;
1915  (*consdata)->scoverrowssize = 0;
1916  (*consdata)->bcoverrows = NULL;
1917  (*consdata)->nbcoverrows = 0;
1918  (*consdata)->bcoverrowssize = 0;
1919  (*consdata)->nvars = nvars;
1920  (*consdata)->varssize = nvars;
1921  (*consdata)->signature = 0;
1922  (*consdata)->validsignature = FALSE;
1923  (*consdata)->normalized = FALSE;
1924  (*consdata)->covercuts = FALSE;
1925  (*consdata)->propagated = FALSE;
1926  (*consdata)->varbounds = FALSE;
1927  (*consdata)->triedsolving = FALSE;
1928 
1929  if( nvars > 0 )
1930  {
1931  assert(vars != NULL); /* for flexelint */
1932 
1933  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1934  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1935  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1936  (*consdata)->linkingconss = NULL;
1937 
1938  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1939  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1940 
1941  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1942  initializeLocks(*consdata, check);
1943 
1944  if( linkingconss != NULL )
1945  {
1946  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1947  }
1948 
1949  /* transform variables, if they are not yet transformed */
1950  if( SCIPisTransformed(scip) )
1951  {
1952  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1953 
1954  /* get transformed variables and do NOT captures these */
1955  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1956 
1957  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1958  * been multi-aggregated
1959  */
1960  for( v = 0; v < nvars; ++v )
1961  {
1962  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1963  }
1964 
1965  if( linkingconss != NULL )
1966  {
1967  /* get transformed constraints and captures these */
1968  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1969 
1970  for( v = 0; v < nvars; ++v )
1971  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1972  }
1973  }
1974  }
1975  else
1976  {
1977  (*consdata)->vars = NULL;
1978  (*consdata)->downlocks = NULL;
1979  (*consdata)->uplocks = NULL;
1980  (*consdata)->demands = NULL;
1981  (*consdata)->durations = NULL;
1982  (*consdata)->linkingconss = NULL;
1983  }
1984 
1985  /* initialize values for running propagation algorithms efficiently */
1986  (*consdata)->resstrength1 = -1.0;
1987  (*consdata)->resstrength2 = -1.0;
1988  (*consdata)->cumfactor1 = -1.0;
1989  (*consdata)->disjfactor1 = -1.0;
1990  (*consdata)->disjfactor2 = -1.0;
1991  (*consdata)->estimatedstrength = -1.0;
1992 
1993  SCIPstatistic( (*consdata)->maxpeak = -1 );
1994 
1995  return SCIP_OKAY;
1996 }
1997 
1998 /** releases LP rows of constraint data and frees rows array */
1999 static
2001  SCIP* scip, /**< SCIP data structure */
2002  SCIP_CONSDATA** consdata /**< constraint data */
2003  )
2004 {
2005  int r;
2006 
2007  assert(consdata != NULL);
2008  assert(*consdata != NULL);
2009 
2010  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2011  {
2012  assert((*consdata)->demandrows[r] != NULL);
2013  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2014  }
2015 
2016  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2017 
2018  (*consdata)->ndemandrows = 0;
2019  (*consdata)->demandrowssize = 0;
2020 
2021  /* free rows of cover cuts */
2022  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2023  {
2024  assert((*consdata)->scoverrows[r] != NULL);
2025  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2026  }
2027 
2028  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2029 
2030  (*consdata)->nscoverrows = 0;
2031  (*consdata)->scoverrowssize = 0;
2032 
2033  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2034  {
2035  assert((*consdata)->bcoverrows[r] != NULL);
2036  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2037  }
2038 
2039  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2040 
2041  (*consdata)->nbcoverrows = 0;
2042  (*consdata)->bcoverrowssize = 0;
2043 
2044  (*consdata)->covercuts = FALSE;
2045 
2046  return SCIP_OKAY;
2047 }
2048 
2049 /** frees a cumulative constraint data */
2050 static
2052  SCIP* scip, /**< SCIP data structure */
2053  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2054  )
2055 {
2056  int varssize;
2057  int nvars;
2058 
2059  assert(consdata != NULL);
2060  assert(*consdata != NULL);
2061 
2062  nvars = (*consdata)->nvars;
2063  varssize = (*consdata)->varssize;
2064 
2065  if( varssize > 0 )
2066  {
2067  int v;
2068 
2069  /* release and free the rows */
2070  SCIP_CALL( consdataFreeRows(scip, consdata) );
2071 
2072  /* release the linking constraints if they were generated */
2073  if( (*consdata)->linkingconss != NULL )
2074  {
2075  for( v = nvars-1; v >= 0; --v )
2076  {
2077  assert((*consdata)->linkingconss[v] != NULL );
2078  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2079  }
2080 
2081  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2082  }
2083 
2084  /* free arrays */
2085  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2086  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2087  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2088  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2089  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2090  }
2091 
2092  /* free memory */
2093  SCIPfreeBlockMemory(scip, consdata);
2094 
2095  return SCIP_OKAY;
2096 }
2097 
2098 /** prints cumulative constraint to file stream */
2099 static
2100 void consdataPrint(
2101  SCIP* scip, /**< SCIP data structure */
2102  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2103  FILE* file /**< output file (or NULL for standard output) */
2104  )
2105 {
2106  int v;
2107 
2108  assert(consdata != NULL);
2109 
2110  /* print coefficients */
2111  SCIPinfoMessage( scip, file, "cumulative(");
2112 
2113  for( v = 0; v < consdata->nvars; ++v )
2114  {
2115  assert(consdata->vars[v] != NULL);
2116  if( v > 0 )
2117  SCIPinfoMessage(scip, file, ", ");
2118  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2119  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2120  consdata->durations[v], consdata->demands[v]);
2121  }
2122  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2123 }
2124 
2125 /** deletes coefficient at given position from constraint data */
2126 static
2128  SCIP* scip, /**< SCIP data structure */
2129  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2130  SCIP_CONS* cons, /**< knapsack constraint */
2131  int pos /**< position of coefficient to delete */
2132  )
2133 {
2134  SCIP_CONSHDLR* conshdlr;
2135  SCIP_CONSHDLRDATA* conshdlrdata;
2136 
2137  assert(scip != NULL);
2138  assert(consdata != NULL);
2139  assert(cons != NULL);
2140  assert(SCIPconsIsTransformed(cons));
2141  assert(!SCIPinProbing(scip));
2142 
2143  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2144  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2145 
2146  /* remove the rounding locks for the deleted variable */
2147  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2148 
2149  consdata->downlocks[pos] = FALSE;
2150  consdata->uplocks[pos] = FALSE;
2151 
2152  if( consdata->linkingconss != NULL )
2153  {
2154  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2155  }
2156 
2157  /* get event handler */
2158  conshdlr = SCIPconsGetHdlr(cons);
2159  assert(conshdlr != NULL);
2160  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2161  assert(conshdlrdata != NULL);
2162  assert(conshdlrdata->eventhdlr != NULL);
2163 
2164  /* drop events */
2165  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2166 
2167  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2168  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2169 
2170  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2171  * position
2172  */
2173  if( pos != consdata->nvars - 1 )
2174  {
2175  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2176  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2177  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2178  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2179  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2180 
2181  if( consdata->linkingconss != NULL )
2182  {
2183  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2184  }
2185  }
2186 
2187  consdata->nvars--;
2188  consdata->validsignature = FALSE;
2189  consdata->normalized = FALSE;
2190 
2191  return SCIP_OKAY;
2192 }
2193 
2194 /** collect linking constraints for each integer variable */
2195 static
2197  SCIP* scip, /**< SCIP data structure */
2198  SCIP_CONSDATA* consdata /**< pointer to consdata */
2199  )
2200 {
2201  int nvars;
2202  int v;
2203 
2204  assert(scip != NULL);
2205  assert(consdata != NULL);
2206 
2207  nvars = consdata->nvars;
2208  assert(nvars > 0);
2209  assert(consdata->linkingconss == NULL);
2210 
2211  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2212 
2213  for( v = 0; v < nvars; ++v )
2214  {
2215  SCIP_CONS* cons;
2216  SCIP_VAR* var;
2217 
2218  var = consdata->vars[v];
2219  assert(var != NULL);
2220 
2221  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2222 
2223  /* create linking constraint if it does not exist yet */
2224  if( !SCIPexistsConsLinking(scip, var) )
2225  {
2226  char name[SCIP_MAXSTRLEN];
2227 
2228  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2229 
2230  /* creates and captures an linking constraint */
2231  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2232  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2233  SCIP_CALL( SCIPaddCons(scip, cons) );
2234  consdata->linkingconss[v] = cons;
2235  }
2236  else
2237  {
2238  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2239  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2240  }
2241 
2242  assert(SCIPexistsConsLinking(scip, var));
2243  assert(consdata->linkingconss[v] != NULL);
2244  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2245  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2246  }
2247 
2248  return SCIP_OKAY;
2249 }
2250 
2251 /**@} */
2252 
2253 
2254 /**@name Check methods
2255  *
2256  * @{
2257  */
2258 
2259 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2260  * given solution is satisfied
2261  */
2262 static
2264  SCIP* scip, /**< SCIP data structure */
2265  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2266  int nvars, /**< number of variables (jobs) */
2267  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2268  int* durations, /**< array containing corresponding durations */
2269  int* demands, /**< array containing corresponding demands */
2270  int capacity, /**< available cumulative capacity */
2271  int hmin, /**< left bound of time axis to be considered (including hmin) */
2272  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2273  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2274  SCIP_CONS* cons, /**< constraint which is checked */
2275  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2276  )
2277 {
2278  int* startsolvalues; /* stores when each job is starting */
2279  int* endsolvalues; /* stores when each job ends */
2280  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2281  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2282 
2283  int freecapacity;
2284  int curtime; /* point in time which we are just checking */
2285  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2286  int j;
2287 
2288  SCIP_Real absviol;
2289  SCIP_Real relviol;
2290 
2291  assert(scip != NULL);
2292  assert(violated != NULL);
2293 
2294  (*violated) = FALSE;
2295 
2296  if( nvars == 0 )
2297  return SCIP_OKAY;
2298 
2299  assert(vars != NULL);
2300  assert(demands != NULL);
2301  assert(durations != NULL);
2302 
2303  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2304  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2305  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2306  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2307  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2308 
2309  /* assign variables, start and endpoints to arrays */
2310  for ( j = 0; j < nvars; ++j )
2311  {
2312  int solvalue;
2313 
2314  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2315  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2316 
2317  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2318 
2319  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2320  * jobs which start before hmin to hmin
2321  */
2322  startsolvalues[j] = MAX(solvalue, hmin);
2323  startindices[j] = j;
2324 
2325  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2326  endindices[j] = j;
2327  }
2328 
2329  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2330  * corresponding indices in the same way)
2331  */
2332  SCIPsortIntInt(startsolvalues, startindices, nvars);
2333  SCIPsortIntInt(endsolvalues, endindices, nvars);
2334 
2335  endindex = 0;
2336  freecapacity = capacity;
2337  absviol = 0.0;
2338  relviol = 0.0;
2339 
2340  /* check each start point of a job whether the capacity is kept or not */
2341  for( j = 0; j < nvars; ++j )
2342  {
2343  /* only check intervals [hmin,hmax) */
2344  curtime = startsolvalues[j];
2345 
2346  if( curtime >= hmax )
2347  break;
2348 
2349  /* subtract all capacity needed up to this point */
2350  freecapacity -= demands[startindices[j]];
2351  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2352  {
2353  j++;
2354  freecapacity -= demands[startindices[j]];
2355  }
2356 
2357  /* free all capacity usages of jobs that are no longer running */
2358  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2359  {
2360  freecapacity += demands[endindices[endindex]];
2361  ++endindex;
2362  }
2363  assert(freecapacity <= capacity);
2364 
2365  /* update absolute and relative violation */
2366  if( absviol < (SCIP_Real) (-freecapacity) )
2367  {
2368  absviol = -freecapacity;
2369  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2370  }
2371 
2372  /* check freecapacity to be smaller than zero */
2373  if( freecapacity < 0 && curtime >= hmin )
2374  {
2375  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2376  (*violated) = TRUE;
2377 
2378  if( printreason )
2379  {
2380  int i;
2381 
2382  /* first state the violated constraints */
2383  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2384 
2385  /* second state the reason */
2386  SCIPinfoMessage(scip, NULL,
2387  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2388  curtime, capacity, capacity - freecapacity);
2389 
2390  for( i = 0; i <= j; ++i )
2391  {
2392  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2393  {
2394  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2395  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2396  demands[startindices[i]]);
2397  }
2398  }
2399  }
2400  break;
2401  }
2402  } /*lint --e{850}*/
2403 
2404  /* update constraint violation in solution */
2405  if( sol != NULL )
2406  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2407 
2408  /* free all buffer arrays */
2409  SCIPfreeBufferArray(scip, &endindices);
2410  SCIPfreeBufferArray(scip, &startindices);
2411  SCIPfreeBufferArray(scip, &endsolvalues);
2412  SCIPfreeBufferArray(scip, &startsolvalues);
2413 
2414  return SCIP_OKAY;
2415 }
2416 
2417 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2418  * least zero or not. If not (*violated) is set to TRUE
2419  */
2420 static
2422  SCIP* scip, /**< SCIP data structure */
2423  SCIP_CONS* cons, /**< constraint to be checked */
2424  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2425  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2426  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2427  )
2428 {
2429  SCIP_CONSDATA* consdata;
2430 
2431  assert(scip != NULL);
2432  assert(cons != NULL);
2433  assert(violated != NULL);
2434 
2435  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2436 
2437  consdata = SCIPconsGetData(cons);
2438  assert(consdata != NULL);
2439 
2440  /* check the cumulative condition */
2441  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2442  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2443  violated, cons, printreason) );
2444 
2445  return SCIP_OKAY;
2446 }
2447 
2448 /**@} */
2449 
2450 /**@name Conflict analysis
2451  *
2452  * @{
2453  */
2454 
2455 /** resolves the propagation of the core time algorithm */
2456 static
2458  SCIP* scip, /**< SCIP data structure */
2459  int nvars, /**< number of start time variables (activities) */
2460  SCIP_VAR** vars, /**< array of start time variables */
2461  int* durations, /**< array of durations */
2462  int* demands, /**< array of demands */
2463  int capacity, /**< cumulative capacity */
2464  int hmin, /**< left bound of time axis to be considered (including hmin) */
2465  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2466  SCIP_VAR* infervar, /**< inference variable */
2467  int inferdemand, /**< demand of the inference variable */
2468  int inferpeak, /**< time point which causes the propagation */
2469  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2470  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2471  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2472  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2473  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2474  )
2475 {
2476  SCIP_VAR* var;
2477  SCIP_Bool* reported;
2478  int duration;
2479  int maxlst;
2480  int minect;
2481  int ect;
2482  int lst;
2483  int j;
2484 
2485  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2486 
2487  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2488  SCIPvarGetName(infervar), inferdemand, inferpeak);
2489  assert(nvars > 0);
2490 
2491  /* adjusted capacity */
2492  capacity -= inferdemand;
2493  maxlst = INT_MIN;
2494  minect = INT_MAX;
2495 
2496  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2497  BMSclearMemoryArray(reported, nvars);
2498 
2499  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2500  * inference peak and those where the current conflict bounds provide a core at the inference peak
2501  */
2502  for( j = 0; j < nvars && capacity >= 0; ++j )
2503  {
2504  var = vars[j];
2505  assert(var != NULL);
2506 
2507  /* skip inference variable */
2508  if( var == infervar )
2509  continue;
2510 
2511  duration = durations[j];
2512  assert(duration > 0);
2513 
2514  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2515  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2516  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2517  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2518  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2519 
2520  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2522  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2523 
2524  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2525  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2526 
2527  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2528  * that job without adding it the explanation
2529  */
2530  if( inferpeak < ect && lst <= inferpeak )
2531  {
2532  capacity -= demands[j];
2533  reported[j] = TRUE;
2534 
2535  maxlst = MAX(maxlst, lst);
2536  minect = MIN(minect, ect);
2537  assert(maxlst < minect);
2538 
2539  if( explanation != NULL )
2540  explanation[j] = TRUE;
2541 
2542  continue;
2543  }
2544 
2545  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2546  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2547  * not part of the conflict yet we get the global bounds back.
2548  */
2549  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2550  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2551 
2552  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2553  * of that job without and collect the job as part of the explanation
2554  *
2555  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2556  */
2557  if( inferpeak < ect && lst <= inferpeak )
2558  {
2559  capacity -= demands[j];
2560  reported[j] = TRUE;
2561 
2562  maxlst = MAX(maxlst, lst);
2563  minect = MIN(minect, ect);
2564  assert(maxlst < minect);
2565 
2566  if( explanation != NULL )
2567  explanation[j] = TRUE;
2568  }
2569  }
2570 
2571  if( capacity >= 0 )
2572  {
2573  int* cands;
2574  int* canddemands;
2575  int ncands;
2576  int c;
2577 
2578  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2579  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2580  ncands = 0;
2581 
2582  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2583  for( j = 0; j < nvars; ++j )
2584  {
2585  var = vars[j];
2586  assert(var != NULL);
2587 
2588  /* skip inference variable */
2589  if( var == infervar || reported[j] )
2590  continue;
2591 
2592  duration = durations[j];
2593  assert(duration > 0);
2594 
2595  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2596  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2597  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2598  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2599  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2600 
2601  /* collect local core information */
2602  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2603  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2604 
2605  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2606  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2607  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2608 
2609  /* check if the inference peak is part of the core */
2610  if( inferpeak < ect && lst <= inferpeak )
2611  {
2612  cands[ncands] = j;
2613  canddemands[ncands] = demands[j];
2614  ncands++;
2615 
2616  capacity -= demands[j];
2617  }
2618  }
2619 
2620  /* sort candidates indices w.r.t. their demands */
2621  SCIPsortDownIntInt(canddemands, cands, ncands);
2622 
2623  assert(capacity < 0);
2624  assert(ncands > 0);
2625 
2626  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2627  while( capacity + canddemands[ncands-1] < 0 )
2628  {
2629  ncands--;
2630  capacity += canddemands[ncands];
2631  assert(ncands > 0);
2632  }
2633 
2634  /* compute the size (number of time steps) of the job cores */
2635  for( c = 0; c < ncands; ++c )
2636  {
2637  var = vars[cands[c]];
2638  assert(var != NULL);
2639 
2640  duration = durations[cands[c]];
2641 
2642  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2643  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2644 
2645  maxlst = MAX(maxlst, lst);
2646  minect = MIN(minect, ect);
2647  assert(maxlst < minect);
2648  }
2649 
2650  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2651  assert(inferpeak >= maxlst);
2652  assert(inferpeak < minect);
2653 
2654  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2655  if( relaxedpeak < inferpeak )
2656  {
2657  inferpeak = MAX(maxlst, relaxedpeak);
2658  }
2659  else if( relaxedpeak > inferpeak )
2660  {
2661  inferpeak = MIN(minect-1, relaxedpeak);
2662  }
2663  assert(inferpeak >= hmin);
2664  assert(inferpeak < hmax);
2665  assert(inferpeak >= maxlst);
2666  assert(inferpeak < minect);
2667 
2668  /* post all necessary bound changes */
2669  for( c = 0; c < ncands; ++c )
2670  {
2671  var = vars[cands[c]];
2672  assert(var != NULL);
2673 
2674  if( usebdwidening )
2675  {
2676  duration = durations[cands[c]];
2677 
2678  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2679  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2680  }
2681  else
2682  {
2683  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2684  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2685  }
2686 
2687  if( explanation != NULL )
2688  explanation[cands[c]] = TRUE;
2689  }
2690 
2691  SCIPfreeBufferArray(scip, &canddemands);
2692  SCIPfreeBufferArray(scip, &cands);
2693  }
2694 
2695  SCIPfreeBufferArray(scip, &reported);
2696 
2697  if( provedpeak != NULL )
2698  *provedpeak = inferpeak;
2699 
2700  return SCIP_OKAY;
2701 }
2702 
2703 #if 0
2704 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2705  * energy in total and for bound change is enough
2706  */
2707 static
2708 SCIP_RETCODE resolvePropagationEdgeFinding(
2709  SCIP* scip, /**< SCIP data structure */
2710  int nvars, /**< number of start time variables (activities) */
2711  SCIP_VAR** vars, /**< array of start time variables */
2712  int* durations, /**< array of durations */
2713  int hmin, /**< left bound of time axis to be considered (including hmin) */
2714  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2715  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2716  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2717  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2718  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2719  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2720  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2721  )
2722 {
2723  int est;
2724  int lct;
2725  int j;
2726 
2727  /* ???????????????????? do bound widening */
2728 
2729  assert(scip != NULL);
2730  assert(nvars > 0);
2731  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2732 
2733  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2734 
2735  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2736  {
2737  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2738  }
2739  else
2740  {
2741  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2742  }
2743 
2744  est = inferInfoGetData1(inferinfo);
2745  lct = inferInfoGetData2(inferinfo);
2746  assert(est < lct);
2747 
2748  /* collect the energies of all variables in [est_omega, lct_omega] */
2749  for( j = 0; j < nvars; ++j )
2750  {
2751  SCIP_VAR* var;
2752  SCIP_Bool left;
2753  SCIP_Bool right;
2754  int duration;
2755  int lb;
2756  int ub;
2757 
2758  var = vars[j];
2759  assert(var != NULL);
2760 
2761  if( var == infervar )
2762  {
2763  if( explanation != NULL )
2764  explanation[j] = TRUE;
2765 
2766  continue;
2767  }
2768 
2769  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2770  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2771 
2772  duration = durations[j];
2773  assert(duration > 0);
2774 
2775  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2776  * since we use adjusted jobs during the propagation
2777  */
2778  left = (est == hmin && lb + duration > hmin) || lb >= est;
2779 
2780  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2781  * since we use adjusted jobs during the propagation
2782  */
2783  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2784 
2785  /* store all jobs running in [est_omega; lct_omega] */
2786  if( left && right )
2787  {
2788  /* check if bound widening should be used */
2789  if( usebdwidening )
2790  {
2791  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2792  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2793  }
2794  else
2795  {
2796  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2797  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2798  }
2799 
2800  if( explanation != NULL )
2801  explanation[j] = TRUE;
2802  }
2803  }
2804 
2805  return SCIP_OKAY;
2806 }
2807 #endif
2808 
2809 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2810 static
2811 int computeOverlap(
2812  int begin, /**< begin of the times interval */
2813  int end, /**< end of time interval */
2814  int est, /**< earliest start time */
2815  int lst, /**< latest start time */
2816  int duration /**< duration of the job */
2817  )
2818 {
2819  int left;
2820  int right;
2821  int ect;
2822  int lct;
2823 
2824  ect = est + duration;
2825  lct = lst + duration;
2826 
2827  /* check if job runs completely within [begin,end) */
2828  if( lct <= end && est >= begin )
2829  return duration;
2830 
2831  assert(lst <= end && ect >= begin);
2832 
2833  left = ect - begin;
2834  assert(left > 0);
2835 
2836  right = end - lst;
2837  assert(right > 0);
2838 
2839  return MIN3(left, right, end - begin);
2840 }
2841 
2842 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2843  * reason
2844  *
2845  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2846  */
2847 static
2849  SCIP* scip, /**< SCIP data structure */
2850  int nvars, /**< number of start time variables (activities) */
2851  SCIP_VAR** vars, /**< array of start time variables */
2852  int* durations, /**< array of durations */
2853  int* demands, /**< array of demands */
2854  int capacity, /**< capacity of the cumulative condition */
2855  int begin, /**< begin of the time window */
2856  int end, /**< end of the time window */
2857  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2858  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2859  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2860  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2861  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2862  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2863  )
2864 {
2865  int* locenergies;
2866  int* overlaps;
2867  int* idxs;
2868 
2869  int requiredenergy;
2870  int v;
2871 
2872  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2873  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2874  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2875 
2876  /* energy which needs be explained */
2877  requiredenergy = (end - begin) * capacity;
2878 
2879  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %d)\n", begin, end, capacity, requiredenergy);
2880 
2881  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2882  * takes
2883  */
2884  for( v = 0; v < nvars; ++v )
2885  {
2886  SCIP_VAR* var;
2887  int glbenergy;
2888  int duration;
2889  int demand;
2890  int est;
2891  int lst;
2892 
2893  var = vars[v];
2894  assert(var != NULL);
2895 
2896  locenergies[v] = 0;
2897  overlaps[v] = 0;
2898  idxs[v] = v;
2899 
2900  demand = demands[v];
2901  assert(demand > 0);
2902 
2903  duration = durations[v];
2904  assert(duration > 0);
2905 
2906  /* check if the variable equals the inference variable (the one which was propagated) */
2907  if( infervar == var )
2908  {
2909  int overlap;
2910  int right;
2911  int left;
2912 
2913  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2914 
2915  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2916  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2917  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2918 
2919  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2920  * which is necessary from the inference variable
2921  */
2922  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2923  {
2924  int lct;
2925 
2926  /* get the latest start time of the infer start time variable before the propagation took place */
2927  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2928 
2929  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2930  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2931  * scheduled w.r.t. its latest start time
2932  */
2933  assert(lst < end);
2934 
2935  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2936  * interval (before the propagation)
2937  */
2938  right = MIN3(end - lst, end - begin, duration);
2939 
2940  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2941  assert(right > 0);
2942 
2943  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2944  assert(begin <= lct);
2945  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2946 
2947  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2948  left = MIN(lct - begin + 1, end - begin);
2949  assert(left > 0);
2950 
2951  /* compute the minimum overlap; */
2952  overlap = MIN(left, right);
2953  assert(overlap > 0);
2954  assert(overlap <= end - begin);
2955  assert(overlap <= duration);
2956 
2957  if( usebdwidening )
2958  {
2959  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2960  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2961  }
2962  else
2963  {
2964  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2965  }
2966  }
2967  else
2968  {
2969  int ect;
2970 
2971  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2972 
2973  /* get the earliest completion time of the infer start time variable before the propagation took place */
2974  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2975 
2976  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2977  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2978  * the job is scheduled w.r.t. its earliest start time
2979  */
2980  assert(ect > begin);
2981 
2982  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2983  * interval (before the propagation)
2984  */
2985  left = MIN3(ect - begin, end - begin, duration);
2986 
2987  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2988  assert(left > 0);
2989 
2990  est = SCIPconvertRealToInt(scip, relaxedbd);
2991  assert(end >= est);
2992  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2993 
2994  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2995  right = MIN(end - est + 1, end - begin);
2996  assert(right > 0);
2997 
2998  /* compute the minimum overlap */
2999  overlap = MIN(left, right);
3000  assert(overlap > 0);
3001  assert(overlap <= end - begin);
3002  assert(overlap <= duration);
3003 
3004  if( usebdwidening )
3005  {
3006  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3007  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3008  }
3009  else
3010  {
3011  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3012  }
3013  }
3014 
3015  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3016  requiredenergy -= overlap * demand;
3017 
3018  if( explanation != NULL )
3019  explanation[v] = TRUE;
3020 
3021  continue;
3022  }
3023 
3024  /* global time points */
3025  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3026  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3027 
3028  glbenergy = 0;
3029 
3030  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3031  * time window
3032  */
3033  if( est + duration > begin && lst < end )
3034  {
3035  /* evaluated global contribution */
3036  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3037 
3038  /* remove the globally available energy form the required energy */
3039  requiredenergy -= glbenergy;
3040 
3041  if( explanation != NULL )
3042  explanation[v] = TRUE;
3043  }
3044 
3045  /* local time points */
3046  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3047  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3048 
3049  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3050  * time window
3051  */
3052  if( est + duration > begin && lst < end )
3053  {
3054  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3055 
3056  /* evaluated additionally local energy contribution */
3057  locenergies[v] = overlaps[v] * demand - glbenergy;
3058  assert(locenergies[v] >= 0);
3059  }
3060  }
3061 
3062  /* sort the variable contributions w.r.t. additional local energy contributions */
3063  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3064 
3065  /* add local energy contributions until an overload is implied */
3066  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3067  {
3068  SCIP_VAR* var;
3069  int duration;
3070  int overlap;
3071  int relaxlb;
3072  int relaxub;
3073  int idx;
3074 
3075  idx = idxs[v];
3076  assert(idx >= 0 && idx < nvars);
3077 
3078  var = vars[idx];
3079  assert(var != NULL);
3080  assert(var != infervar);
3081 
3082  duration = durations[idx];
3083  assert(duration > 0);
3084 
3085  overlap = overlaps[v];
3086  assert(overlap > 0);
3087 
3088  requiredenergy -= locenergies[v];
3089 
3090  if( requiredenergy < -1 )
3091  {
3092  int demand;
3093 
3094  demand = demands[idx];
3095  assert(demand > 0);
3096 
3097  overlap += (int)((requiredenergy + 1) / demand);
3098 
3099 #ifndef NDEBUG
3100  requiredenergy += locenergies[v];
3101  requiredenergy -= overlap * demand;
3102  assert(requiredenergy < 0);
3103 #endif
3104  }
3105  assert(overlap > 0);
3106 
3107  relaxlb = begin - duration + overlap;
3108  relaxub = end - overlap;
3109 
3110  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3111  SCIPvarGetName(var),
3114  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3115  relaxlb, relaxub, demands[idx], duration);
3116 
3117  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3118  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3119 
3120  if( explanation != NULL )
3121  explanation[idx] = TRUE;
3122  }
3123 
3124  assert(requiredenergy < 0);
3125 
3126  SCIPfreeBufferArray(scip, &idxs);
3127  SCIPfreeBufferArray(scip, &overlaps);
3128  SCIPfreeBufferArray(scip, &locenergies);
3129 
3130  return SCIP_OKAY;
3131 }
3132 
3133 /** resolve propagation w.r.t. the cumulative condition */
3134 static
3136  SCIP* scip, /**< SCIP data structure */
3137  int nvars, /**< number of start time variables (activities) */
3138  SCIP_VAR** vars, /**< array of start time variables */
3139  int* durations, /**< array of durations */
3140  int* demands, /**< array of demands */
3141  int capacity, /**< cumulative capacity */
3142  int hmin, /**< left bound of time axis to be considered (including hmin) */
3143  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3144  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3145  INFERINFO inferinfo, /**< the user information */
3146  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3147  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3148  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3149  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3150  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3151  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3152  )
3153 {
3154  switch( inferInfoGetProprule(inferinfo) )
3155  {
3156  case PROPRULE_1_CORETIMES:
3157  {
3158  int inferdemand;
3159  int inferduration;
3160  int inferpos;
3161  int inferpeak;
3162  int relaxedpeak;
3163  int provedpeak;
3164 
3165  /* get the position of the inferred variable in the vars array */
3166  inferpos = inferInfoGetData1(inferinfo);
3167  if( inferpos >= nvars || vars[inferpos] != infervar )
3168  {
3169  /* find inference variable in constraint */
3170  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3171  {}
3172  }
3173  assert(inferpos < nvars);
3174  assert(vars[inferpos] == infervar);
3175 
3176  inferdemand = demands[inferpos];
3177  inferduration = durations[inferpos];
3178 
3179  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3180  {
3181  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3182  * the inference variable
3183  */
3184  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3185 
3186  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3187  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3188  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3189 
3190  /* get the inference peak that the time point which lead to the that propagtion */
3191  inferpeak = inferInfoGetData2(inferinfo);
3192  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3193  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3194  */
3195  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3196  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3197 
3198  /* make sure that the relaxed peak is part of the effective horizon */
3199  relaxedpeak = MIN(relaxedpeak, hmax-1);
3200 
3201  /* make sure that relaxed peak is not larger than the infer peak
3202  *
3203  * This can happen in case the variable is not an active variable!
3204  */
3205  relaxedpeak = MAX(relaxedpeak, inferpeak);
3206  assert(relaxedpeak >= inferpeak);
3207  assert(relaxedpeak >= hmin);
3208  }
3209  else
3210  {
3211  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3212 
3213  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3214  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3215  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3216 
3217  /* get the time interval where the job could not be scheduled */
3218  inferpeak = inferInfoGetData2(inferinfo);
3219  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3220  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3221  */
3222  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3223  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3224 
3225  /* make sure that the relaxed peak is part of the effective horizon */
3226  relaxedpeak = MAX(relaxedpeak, hmin);
3227 
3228  /* make sure that relaxed peak is not larger than the infer peak
3229  *
3230  * This can happen in case the variable is not an active variable!
3231  */
3232  relaxedpeak = MIN(relaxedpeak, inferpeak);
3233  assert(relaxedpeak < hmax);
3234  }
3235 
3236  /* resolves the propagation of the core time algorithm */
3237  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3238  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3239 
3240  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3241  {
3242  if( usebdwidening )
3243  {
3244  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3245  }
3246  else
3247  {
3248  /* old upper bound of variable itself is part of the explanation */
3249  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3250  }
3251  }
3252  else
3253  {
3254  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3255 
3256  if( usebdwidening )
3257  {
3258  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3259  }
3260  else
3261  {
3262  /* old lower bound of variable itself is part of the explanation */
3263  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3264  }
3265  }
3266 
3267  if( explanation != NULL )
3268  explanation[inferpos] = TRUE;
3269 
3270  break;
3271  }
3273  case PROPRULE_3_TTEF:
3274  {
3275  int begin;
3276  int end;
3277 
3278  begin = inferInfoGetData1(inferinfo);
3279  end = inferInfoGetData2(inferinfo);
3280  assert(begin < end);
3281 
3282  begin = MAX(begin, hmin);
3283  end = MIN(end, hmax);
3284 
3285  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3286  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3287 
3288  break;
3289  }
3290 
3291  default:
3292  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3293  SCIPABORT();
3294  return SCIP_INVALIDDATA; /*lint !e527*/
3295  }
3296 
3297  (*result) = SCIP_SUCCESS;
3298 
3299  return SCIP_OKAY;
3300 }
3301 
3302 /**@} */
3303 
3304 
3305 /**@name Enforcement methods
3306  *
3307  * @{
3308  */
3309 
3310 /** apply all fixings which are given by the alternative bounds */
3311 static
3313  SCIP* scip, /**< SCIP data structure */
3314  SCIP_VAR** vars, /**< array of active variables */
3315  int nvars, /**< number of active variables */
3316  int* alternativelbs, /**< alternative lower bounds */
3317  int* alternativeubs, /**< alternative lower bounds */
3318  int* downlocks, /**< number of constraints with down lock participating by the computation */
3319  int* uplocks, /**< number of constraints with up lock participating by the computation */
3320  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3321  )
3322 {
3323  int v;
3324 
3325  for( v = 0; v < nvars; ++v )
3326  {
3327  SCIP_VAR* var;
3328  SCIP_Real objval;
3329 
3330  var = vars[v];
3331  assert(var != NULL);
3332 
3333  objval = SCIPvarGetObj(var);
3334 
3335  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3336  {
3337  int ub;
3338 
3339  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3340 
3341  if( alternativelbs[v] <= ub )
3342  {
3343  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3344  (*branched) = TRUE;
3345 
3346  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3347  SCIPvarGetLbLocal(var), alternativelbs[v]);
3348 
3349  return SCIP_OKAY;
3350  }
3351  }
3352 
3353  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3354  {
3355  int lb;
3356 
3357  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3358 
3359  if( alternativeubs[v] >= lb )
3360  {
3361  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3362  (*branched) = TRUE;
3363 
3364  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3365  alternativeubs[v], SCIPvarGetUbLocal(var));
3366 
3367  return SCIP_OKAY;
3368  }
3369  }
3370  }
3371 
3372  return SCIP_OKAY;
3373 }
3374 
3375 /** remove the capacity requirments for all job which start at the curtime */
3376 static
3378  SCIP_CONSDATA* consdata, /**< constraint data */
3379  int curtime, /**< current point in time */
3380  int* starttimes, /**< array of start times */
3381  int* startindices, /**< permutation with respect to the start times */
3382  int* freecapacity, /**< pointer to store the resulting free capacity */
3383  int* idx, /**< pointer to index in start time array */
3384  int nvars /**< number of vars in array of starttimes and startindices */
3385  )
3386 {
3387 #if defined SCIP_DEBUG && !defined NDEBUG
3388  int oldidx;
3389 
3390  assert(idx != NULL);
3391  oldidx = *idx;
3392 #else
3393  assert(idx != NULL);
3394 #endif
3395 
3396  assert(starttimes != NULL);
3397  assert(starttimes != NULL);
3398  assert(freecapacity != NULL);
3399  assert(starttimes[*idx] == curtime);
3400  assert(consdata->demands != NULL);
3401  assert(freecapacity != idx);
3402 
3403  /* subtract all capacity needed up to this point */
3404  (*freecapacity) -= consdata->demands[startindices[*idx]];
3405 
3406  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3407  {
3408  ++(*idx);
3409  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3410  assert(freecapacity != idx);
3411  }
3412 #ifdef SCIP_DEBUG
3413  assert(oldidx <= *idx);
3414 #endif
3415 }
3416 
3417 /** add the capacity requirments for all job which end at the curtime */
3418 static
3419 void addEndingJobDemands(
3420  SCIP_CONSDATA* consdata, /**< constraint data */
3421  int curtime, /**< current point in time */
3422  int* endtimes, /**< array of end times */
3423  int* endindices, /**< permutation with rspect to the end times */
3424  int* freecapacity, /**< pointer to store the resulting free capacity */
3425  int* idx, /**< pointer to index in end time array */
3426  int nvars /**< number of vars in array of starttimes and startindices */
3427  )
3428 {
3429 #if defined SCIP_DEBUG && !defined NDEBUG
3430  int oldidx;
3431  oldidx = *idx;
3432 #endif
3433 
3434  /* free all capacity usages of jobs the are no longer running */
3435  while( endtimes[*idx] <= curtime && *idx < nvars)
3436  {
3437  (*freecapacity) += consdata->demands[endindices[*idx]];
3438  ++(*idx);
3439  }
3440 
3441 #ifdef SCIP_DEBUG
3442  assert(oldidx <= *idx);
3443 #endif
3444 }
3445 
3446 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3447 static
3449  SCIP* scip, /**< SCIP data structure */
3450  SCIP_CONSDATA* consdata, /**< constraint handler data */
3451  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3452  int* timepoint /**< pointer to store the time point of the peak */
3453  )
3454 {
3455  int* starttimes; /* stores when each job is starting */
3456  int* endtimes; /* stores when each job ends */
3457  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3458  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3459 
3460  int nvars; /* number of activities for this constraint */
3461  int freecapacity; /* remaining capacity */
3462  int curtime; /* point in time which we are just checking */
3463  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3464 
3465  int hmin;
3466  int hmax;
3467 
3468  int j;
3469 
3470  assert(consdata != NULL);
3471 
3472  nvars = consdata->nvars;
3473  assert(nvars > 0);
3474 
3475  *timepoint = consdata->hmax;
3476 
3477  assert(consdata->vars != NULL);
3478 
3479  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3480  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3481  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3482  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3483 
3484  /* create event point arrays */
3485  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3486  starttimes, endtimes, startindices, endindices);
3487 
3488  endindex = 0;
3489  freecapacity = consdata->capacity;
3490  hmin = consdata->hmin;
3491  hmax = consdata->hmax;
3492 
3493  /* check each startpoint of a job whether the capacity is kept or not */
3494  for( j = 0; j < nvars; ++j )
3495  {
3496  curtime = starttimes[j];
3497  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3498 
3499  if( curtime >= hmax )
3500  break;
3501 
3502  /* remove the capacity requirments for all job which start at the curtime */
3503  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3504 
3505  /* add the capacity requirments for all job which end at the curtime */
3506  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3507 
3508  assert(freecapacity <= consdata->capacity);
3509  assert(endindex <= nvars);
3510 
3511  /* endindex - points to the next job which will finish */
3512  /* j - points to the last job that has been released */
3513 
3514  /* if free capacity is smaller than zero, then add branching candidates */
3515  if( freecapacity < 0 && curtime >= hmin )
3516  {
3517  *timepoint = curtime;
3518  break;
3519  }
3520  } /*lint --e{850}*/
3521 
3522  /* free all buffer arrays */
3523  SCIPfreeBufferArray(scip, &endindices);
3524  SCIPfreeBufferArray(scip, &startindices);
3525  SCIPfreeBufferArray(scip, &endtimes);
3526  SCIPfreeBufferArray(scip, &starttimes);
3527 
3528  return SCIP_OKAY;
3529 }
3530 
3531 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3532 static
3534  SCIP* scip, /**< SCIP data structure */
3535  SCIP_CONS** conss, /**< constraints to be processed */
3536  int nconss, /**< number of constraints */
3537  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3538  int* nbranchcands /**< pointer to store the number of branching variables */
3539  )
3540 {
3541  SCIP_HASHTABLE* collectedvars;
3542  int c;
3543 
3544  assert(scip != NULL);
3545  assert(conss != NULL);
3546 
3547  /* create a hash table */
3548  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3549  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3550 
3551  assert(scip != NULL);
3552  assert(conss != NULL);
3553 
3554  for( c = 0; c < nconss; ++c )
3555  {
3556  SCIP_CONS* cons;
3557  SCIP_CONSDATA* consdata;
3558 
3559  int curtime;
3560  int j;
3561 
3562  cons = conss[c];
3563  assert(cons != NULL);
3564 
3565  if( !SCIPconsIsActive(cons) )
3566  continue;
3567 
3568  consdata = SCIPconsGetData(cons);
3569  assert(consdata != NULL);
3570 
3571  /* get point in time when capacity is exceeded */
3572  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3573 
3574  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3575  continue;
3576 
3577  /* report all variables that are running at that point in time */
3578  for( j = 0; j < consdata->nvars; ++j )
3579  {
3580  SCIP_VAR* var;
3581  int lb;
3582  int ub;
3583 
3584  var = consdata->vars[j];
3585  assert(var != NULL);
3586 
3587  /* check if the variable was already added */
3588  if( SCIPhashtableExists(collectedvars, (void*)var) )
3589  continue;
3590 
3591  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3592  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3593 
3594  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3595  {
3596  SCIP_Real solval;
3597  SCIP_Real score;
3598 
3599  solval = SCIPgetSolVal(scip, sol, var);
3600  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3601 
3602  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3603  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3604  (*nbranchcands)++;
3605 
3606  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3607  }
3608  }
3609  }
3610 
3611  SCIPhashtableFree(&collectedvars);
3612 
3613  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3614 
3615  return SCIP_OKAY;
3616 }
3617 
3618 /** enforcement of an LP, pseudo, or relaxation solution */
3619 static
3621  SCIP* scip, /**< SCIP data structure */
3622  SCIP_CONS** conss, /**< constraints to be processed */
3623  int nconss, /**< number of constraints */
3624  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3625  SCIP_Bool branch, /**< should branching candidates be collected */
3626  SCIP_RESULT* result /**< pointer to store the result */
3627  )
3628 {
3629  if( branch )
3630  {
3631  int nbranchcands;
3632 
3633  nbranchcands = 0;
3634  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3635 
3636  if( nbranchcands > 0 )
3637  (*result) = SCIP_INFEASIBLE;
3638  }
3639  else
3640  {
3641  SCIP_Bool violated;
3642  int c;
3643 
3644  violated = FALSE;
3645 
3646  /* first check if a constraints is violated */
3647  for( c = 0; c < nconss && !violated; ++c )
3648  {
3649  SCIP_CONS* cons;
3650 
3651  cons = conss[c];
3652  assert(cons != NULL);
3653 
3654  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3655  }
3656 
3657  if( violated )
3658  (*result) = SCIP_INFEASIBLE;
3659  }
3660 
3661  return SCIP_OKAY;
3662 }
3663 
3664 /**@} */
3665 
3666 /**@name Propagation
3667  *
3668  * @{
3669  */
3670 
3671 /** check if cumulative constraint is independently of all other constraints */
3672 static
3674  SCIP* scip, /**< SCIP data structure */
3675  SCIP_CONS* cons /**< cumulative constraint */
3676  )
3677 {
3678  SCIP_CONSDATA* consdata;
3679  SCIP_VAR** vars;
3680  SCIP_Bool* downlocks;
3681  SCIP_Bool* uplocks;
3682  int nvars;
3683  int v;
3684 
3685  consdata = SCIPconsGetData(cons);
3686  assert(consdata != NULL);
3687 
3688  nvars = consdata->nvars;
3689  vars = consdata->vars;
3690  downlocks = consdata->downlocks;
3691  uplocks = consdata->uplocks;
3692 
3693  /* check if the cumulative constraint has the only locks on the involved variables */
3694  for( v = 0; v < nvars; ++v )
3695  {
3696  SCIP_VAR* var;
3697 
3698  var = vars[v];
3699  assert(var != NULL);
3700 
3701  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3702  || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3703  return FALSE;
3704  }
3705 
3706  return TRUE;
3707 }
3708 
3709 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3710  * (dual reductions)
3711  */
3712 static
3714  SCIP* scip, /**< SCIP data structure */
3715  SCIP_CONS* cons, /**< cumulative constraint */
3716  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3717  int* nchgbds, /**< pointer to store the number changed variable bounds */
3718  int* nfixedvars, /**< pointer to count number of fixings */
3719  int* ndelconss, /**< pointer to count number of deleted constraints */
3720  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3721  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3722  )
3723 {
3724  SCIP_CONSDATA* consdata;
3725  SCIP_VAR** vars;
3726  SCIP_Real* objvals;
3727  SCIP_Real* lbs;
3728  SCIP_Real* ubs;
3729  SCIP_Real timelimit;
3730  SCIP_Real memorylimit;
3731  SCIP_Bool solved;
3732  SCIP_Bool error;
3733 
3734  int ncheckconss;
3735  int nvars;
3736  int v;
3737 
3738  assert(scip != NULL);
3739  assert(!SCIPconsIsModifiable(cons));
3740  assert(SCIPgetNConss(scip) > 0);
3741 
3742  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3743  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3744  */
3745  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3746  return SCIP_OKAY;
3747 
3748  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3749  * use the locks to decide for a dual reduction using this constraint;
3750  */
3751  if( !SCIPconsIsChecked(cons) )
3752  return SCIP_OKAY;
3753 
3754  ncheckconss = SCIPgetNCheckConss(scip);
3755 
3756  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3757  * presolved problem do nothing execpt to change the parameter settings
3758  */
3759  if( ncheckconss == 1 )
3760  {
3761  /* shrink the minimal maximum value for the conflict length */
3762  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3763 
3764  /* use only first unique implication point */
3765  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3766 
3767  /* do not use reconversion conflicts */
3768  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3769 
3770  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3771  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3772 
3773  /* increase the number of conflicts which induce a restart */
3774  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3775 
3776  /* weight the variable which made into a conflict */
3777  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3778 
3779  /* do not check pseudo solution (for performance reasons) */
3780  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3781 
3782  /* use value based history to detect a reasonable branching point */
3783  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3784 
3785  /* turn of LP relaxation */
3786  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3787 
3788  /* prefer the down branch in case the value based history does not suggest something */
3789  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3790 
3791  /* accept any bound change */
3792  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3793 
3794  /* allow for at most 10 restart, after that the value based history should be reliable */
3795  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3796 
3797  /* set priority for depth first search to highest possible value */
3798  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3799 
3800  return SCIP_OKAY;
3801  }
3802 
3803  consdata = SCIPconsGetData(cons);
3804  assert(consdata != NULL);
3805 
3806  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3807  * fail on the first place
3808  */
3809  if( consdata->triedsolving )
3810  return SCIP_OKAY;
3811 
3812  /* check if constraint is independently */
3813  if( !isConsIndependently(scip, cons) )
3814  return SCIP_OKAY;
3815 
3816  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3817  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3818  */
3819  consdata->triedsolving = TRUE;
3820 
3821  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3822  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3823  SCIPdebugPrintCons(scip, cons, NULL);
3824 
3825  nvars = consdata->nvars;
3826  vars = consdata->vars;
3827 
3828  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3829  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3830  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3831 
3832  for( v = 0; v < nvars; ++v )
3833  {
3834  SCIP_VAR* var;
3835 
3836  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3837  * array
3838  */
3839  var = vars[v];
3840  assert(var != NULL);
3841 
3842  lbs[v] = SCIPvarGetLbLocal(var);
3843  ubs[v] = SCIPvarGetUbLocal(var);
3844 
3845  objvals[v] = SCIPvarGetObj(var);
3846  }
3847 
3848  /* check whether there is enough time and memory left */
3849  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3850  if( !SCIPisInfinity(scip, timelimit) )
3851  timelimit -= SCIPgetSolvingTime(scip);
3852  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3853 
3854  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3855  if( !SCIPisInfinity(scip, memorylimit) )
3856  {
3857  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3858  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3859  }
3860 
3861  /* solve the cumulative condition separately */
3862  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3863  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3864 
3865  if( !(*cutoff) && !(*unbounded) && !error )
3866  {
3867  SCIP_Bool infeasible;
3868  SCIP_Bool tightened;
3869  SCIP_Bool allfixed;
3870 
3871  allfixed = TRUE;
3872 
3873  for( v = 0; v < nvars; ++v )
3874  {
3875  /* check if variable is fixed */
3876  if( lbs[v] + 0.5 > ubs[v] )
3877  {
3878  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3879  assert(!infeasible);
3880 
3881  if( tightened )
3882  {
3883  (*nfixedvars)++;
3884  consdata->triedsolving = FALSE;
3885  }
3886  }
3887  else
3888  {
3889  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3890  assert(!infeasible);
3891 
3892  if( tightened )
3893  {
3894  (*nchgbds)++;
3895  consdata->triedsolving = FALSE;
3896  }
3897 
3898  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3899  assert(!infeasible);
3900 
3901  if( tightened )
3902  {
3903  (*nchgbds)++;
3904  consdata->triedsolving = FALSE;
3905  }
3906 
3907  allfixed = FALSE;
3908  }
3909  }
3910 
3911  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3912  if( allfixed )
3913  {
3914  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3915  (*ndelconss)++;
3916  }
3917  }
3918 
3919  SCIPfreeBufferArray(scip, &objvals);
3920  SCIPfreeBufferArray(scip, &ubs);
3921  SCIPfreeBufferArray(scip, &lbs);
3922 
3923  return SCIP_OKAY;
3924 }
3925 
3926 /** start conflict analysis to analysis the core insertion which is infeasible */
3927 static
3929  SCIP* scip, /**< SCIP data structure */
3930  int nvars, /**< number of start time variables (activities) */
3931  SCIP_VAR** vars, /**< array of start time variables */
3932  int* durations, /**< array of durations */
3933  int* demands, /**< array of demands */
3934  int capacity, /**< cumulative capacity */
3935  int hmin, /**< left bound of time axis to be considered (including hmin) */
3936  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3937  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3938  int inferduration, /**< duration of the start time variable */
3939  int inferdemand, /**< demand of the start time variable */
3940  int inferpeak, /**< profile preak which causes the infeasibilty */
3941  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3942  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3943  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3944  )
3945 {
3946  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3947  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3948  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3949 
3950  /* initialize conflict analysis if conflict analysis is applicable */
3952  {
3954 
3955  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3956  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3957 
3958  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3959 
3960  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3961  if( usebdwidening )
3962  {
3963  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3964  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3965  }
3966  else
3967  {
3968  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3969  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3970  }
3971 
3972  *initialized = TRUE;
3973  }
3974 
3975  return SCIP_OKAY;
3976 }
3977 
3978 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3979  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3980  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3981  * analysis
3982  */
3983 static
3985  SCIP* scip, /**< SCIP data structure */
3986  int nvars, /**< number of start time variables (activities) */
3987  SCIP_VAR** vars, /**< array of start time variables */
3988  int* durations, /**< array of durations */
3989  int* demands, /**< array of demands */
3990  int capacity, /**< cumulative capacity */
3991  int hmin, /**< left bound of time axis to be considered (including hmin) */
3992  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3993  SCIP_CONS* cons, /**< constraint which is propagated */
3994  SCIP_PROFILE* profile, /**< resource profile */
3995  int idx, /**< position of the variable to propagate */
3996  int* nchgbds, /**< pointer to store the number of bound changes */
3997  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3998  SCIP_Bool* initialized, /**< was conflict analysis initialized */
3999  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4000  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4001  )
4002 {
4003  SCIP_VAR* var;
4004  int ntimepoints;
4005  int duration;
4006  int demand;
4007  int peak;
4008  int newlb;
4009  int est;
4010  int lst;
4011  int pos;
4012 
4013  var = vars[idx];
4014  assert(var != NULL);
4015 
4016  duration = durations[idx];
4017  assert(duration > 0);
4018 
4019  demand = demands[idx];
4020  assert(demand > 0);
4021 
4022  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4023  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4024  ntimepoints = SCIPprofileGetNTimepoints(profile);
4025 
4026  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4027  * load which we have at the earliest start time (lower bound)
4028  */
4029  (void) SCIPprofileFindLeft(profile, est, &pos);
4030 
4031  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4032 
4033  /* we now trying to move the earliest start time in steps of at most "duration" length */
4034  do
4035  {
4036  INFERINFO inferinfo;
4037  SCIP_Bool tightened;
4038  int ect;
4039 
4040 #ifndef NDEBUG
4041  {
4042  /* in debug mode we check that we adjust the search position correctly */
4043  int tmppos;
4044 
4045  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4046  assert(pos == tmppos);
4047  }
4048 #endif
4049  ect = est + duration;
4050  peak = -1;
4051 
4052  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4053  * want a peak which is closest to the earliest completion time
4054  */
4055  do
4056  {
4057  /* check if the profile load conflicts with the demand of the start time variable */
4058  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4059  peak = pos;
4060 
4061  pos++;
4062  }
4063  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4064 
4065  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4066  * conflicting to the core resource profile
4067  */
4068  if( peak == -1 )
4069  break;
4070 
4071  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4072  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4073  * earliest completion time (the remaining move will done in the next loop)
4074  */
4075  newlb = SCIPprofileGetTime(profile, peak+1);
4076  newlb = MIN(newlb, ect);
4077 
4078  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4079  if( newlb > lst )
4080  {
4081  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4082 
4083  /* use conflict analysis to analysis the core insertion which was infeasible */
4084  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4085  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4086 
4087  if( explanation != NULL )
4088  explanation[idx] = TRUE;
4089 
4090  *infeasible = TRUE;
4091 
4092  break;
4093  }
4094 
4095  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4096  * bound change
4097  */
4098  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4099 
4100  /* perform the bound lower bound change */
4101  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4102  assert(tightened);
4103  assert(!(*infeasible));
4104 
4105  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4106  (*nchgbds)++;
4107 
4108  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4110 
4111  /* adjust the earliest start time
4112  *
4113  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4114  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4115  * involved.
4116  */
4117  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4118  assert(est >= newlb);
4119 
4120  /* adjust the search position for the resource profile for the next step */
4121  if( est == SCIPprofileGetTime(profile, peak+1) )
4122  pos = peak + 1;
4123  else
4124  pos = peak;
4125  }
4126  while( est < lst );
4127 
4128  return SCIP_OKAY;
4129 }
4130 
4131 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4132  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4133  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4134  * analysis
4135  */
4136 static
4138  SCIP* scip, /**< SCIP data structure */
4139  SCIP_VAR* var, /**< start time variable to propagate */
4140  int duration, /**< duration of the job */
4141  int demand, /**< demand of the job */
4142  int capacity, /**< cumulative capacity */
4143  SCIP_CONS* cons, /**< constraint which is propagated */
4144  SCIP_PROFILE* profile, /**< resource profile */
4145  int idx, /**< position of the variable to propagate */
4146  int* nchgbds /**< pointer to store the number of bound changes */
4147  )
4148 {
4149  int ntimepoints;
4150  int newub;
4151  int peak;
4152  int pos;
4153  int est;
4154  int lst;
4155  int lct;
4156 
4157  assert(var != NULL);
4158  assert(duration > 0);
4159  assert(demand > 0);
4160 
4161  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4162  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4163 
4164  /* in case the start time variable is fixed do nothing */
4165  if( est == lst )
4166  return SCIP_OKAY;
4167 
4168  ntimepoints = SCIPprofileGetNTimepoints(profile);
4169 
4170  lct = lst + duration;
4171 
4172  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4173  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4174  * position gives us the load which we have at the latest completion time minus one
4175  */
4176  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4177 
4178  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4179  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4180 
4181  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4182  return SCIP_OKAY;
4183 
4184  /* we now trying to move the latest start time in steps of at most "duration" length */
4185  do
4186  {
4187  INFERINFO inferinfo;
4188  SCIP_Bool tightened;
4189  SCIP_Bool infeasible;
4190 
4191  peak = -1;
4192 
4193 #ifndef NDEBUG
4194  {
4195  /* in debug mode we check that we adjust the search position correctly */
4196  int tmppos;
4197 
4198  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4199  assert(pos == tmppos);
4200  }
4201 #endif
4202 
4203  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4204  * want a peak which is closest to the latest start time
4205  */
4206  do
4207  {
4208  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4209  peak = pos;
4210 
4211  pos--;
4212  }
4213  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4214 
4215  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4216  * to the core resource profile
4217  */
4218  if( peak == -1 )
4219  break;
4220 
4221  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4222  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4223  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4224  * doing in the next loop)
4225  */
4226  newub = SCIPprofileGetTime(profile, peak);
4227  newub = MAX(newub, lst) - duration;
4228  assert(newub >= est);
4229 
4230  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4231  * bound change
4232  */
4233  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4234 
4235  /* perform the bound upper bound change */
4236  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4237  assert(tightened);
4238  assert(!infeasible);
4239 
4240  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4241  (*nchgbds)++;
4242 
4243  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4245 
4246  /* adjust the latest start and completion time
4247  *
4248  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4249  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4250  * involved.
4251  */
4252  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4253  assert(lst <= newub);
4254  lct = lst + duration;
4255 
4256  /* adjust the search position for the resource profile for the next step */
4257  if( SCIPprofileGetTime(profile, peak) == lct )
4258  pos = peak - 1;
4259  else
4260  pos = peak;
4261  }
4262  while( est < lst );
4263 
4264  return SCIP_OKAY;
4265 }
4266 
4267 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4268  * points
4269  */
4270 static
4272  SCIP* scip, /**< SCIP data structure */
4273  SCIP_PROFILE* profile, /**< core profile */
4274  int nvars, /**< number of start time variables (activities) */
4275  int* ests, /**< array of sorted earliest start times */
4276  int* lcts, /**< array of sorted latest completion times */
4277  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4278  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4279  )
4280 {
4281  int ntimepoints;
4282  int energy;
4283  int t;
4284  int v;
4285 
4286  ntimepoints = SCIPprofileGetNTimepoints(profile);
4287  t = ntimepoints - 1;
4288  energy = 0;
4289 
4290  /* compute core energy after the earliest start time of each job */
4291  for( v = nvars-1; v >= 0; --v )
4292  {
4293  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4294  {
4295  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4296  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4297  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4298  t--;
4299  }
4300  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4301 
4302  /* maybe ests[j] is in-between two timepoints */
4303  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4304  {
4305  assert(t > 0);
4306  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4307  }
4308  else
4309  coreEnergyAfterEst[v] = energy;
4310  }
4311 
4312  t = ntimepoints - 1;
4313  energy = 0;
4314 
4315  /* compute core energy after the latest completion time of each job */
4316  for( v = nvars-1; v >= 0; --v )
4317  {
4318  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4319  {
4320  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4321  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4322  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4323  t--;
4324  }
4325  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4326 
4327  /* maybe lcts[j] is in-between two timepoints */
4328  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4329  {
4330  assert(t > 0);
4331  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4332  }
4333  else
4334  coreEnergyAfterLct[v] = energy;
4335  }
4336 
4337  return SCIP_OKAY;
4338 }
4339 
4340 /** collect earliest start times, latest completion time, and free energy contributions */
4341 static
4342 void collectDataTTEF(
4343  SCIP* scip, /**< SCIP data structure */
4344  int nvars, /**< number of start time variables (activities) */
4345  SCIP_VAR** vars, /**< array of start time variables */
4346  int* durations, /**< array of durations */
4347  int* demands, /**< array of demands */
4348  int hmin, /**< left bound of time axis to be considered (including hmin) */
4349  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4350  int* permests, /**< array to store the variable positions */
4351  int* ests, /**< array to store earliest start times */
4352  int* permlcts, /**< array to store the variable positions */
4353  int* lcts, /**< array to store latest completion times */
4354  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4355  int* lsts, /**< array to store latest start times of the flexible part of the job */
4356  int* flexenergies /**< array to store the flexible energies of each job */
4357  )
4358 {
4359  int v;
4360 
4361  for( v = 0; v < nvars; ++ v)
4362  {
4363  int duration;
4364  int leftadjust;
4365  int rightadjust;
4366  int core;
4367  int est;
4368  int lct;
4369  int ect;
4370  int lst;
4371 
4372  duration = durations[v];
4373  assert(duration > 0);
4374 
4375  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4376  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4377  ect = est + duration;
4378  lct = lst + duration;
4379 
4380  ests[v] = est;
4381  lcts[v] = lct;
4382  permests[v] = v;
4383  permlcts[v] = v;
4384 
4385  /* compute core time window which lies within the effective horizon */
4386  core = computeCoreWithInterval(hmin, hmax, ect, lst);
4387 
4388  /* compute the number of time steps the job could run before the effective horizon */
4389  leftadjust = MAX(0, hmin - est);
4390 
4391  /* compute the number of time steps the job could run after the effective horizon */
4392  rightadjust = MAX(0, lct - hmax);
4393 
4394  /* compute for each job the energy which is flexible; meaning not part of the core */
4395  flexenergies[v] = duration - leftadjust - rightadjust - core;
4396  flexenergies[v] = MAX(0, flexenergies[v]);
4397  flexenergies[v] *= demands[v];
4398  assert(flexenergies[v] >= 0);
4399 
4400  /* the earliest completion time of the flexible energy */
4401  ects[v] = MIN(ect, lst);
4402 
4403  /* the latest start time of the flexible energy */
4404  lsts[v] = MAX(ect, lst);
4405  }
4406 }
4407 
4408 /** try to tighten the lower bound of the given variable */
4409 static
4411  SCIP* scip, /**< SCIP data structure */
4412  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4413  int nvars, /**< number of start time variables (activities) */
4414  SCIP_VAR** vars, /**< array of start time variables */
4415  int* durations, /**< array of durations */
4416  int* demands, /**< array of demands */
4417  int capacity, /**< cumulative capacity */
4418  int hmin, /**< left bound of time axis to be considered (including hmin) */
4419  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4420  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4421  int duration, /**< duration of the job */
4422  int demand, /**< demand of the job */
4423  int est, /**< earliest start time of the job */
4424  int ect, /**< earliest completion time of the flexible part of the job */
4425  int lct, /**< latest completion time of the job */
4426  int begin, /**< begin of the time window under investigation */
4427  int end, /**< end of the time window under investigation */
4428  int energy, /**< available energy for the flexible part of the hob within the time window */
4429  int* bestlb, /**< pointer to strope the best lower bound change */
4430  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4431  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4432  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4433  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4434  )
4435 {
4436  int newlb;
4437 
4438  assert(begin >= hmin);
4439  assert(end <= hmax);
4440 
4441  /* check if the time-table edge-finding should infer bounds */
4442  if( !conshdlrdata->ttefinfer )
4443  return SCIP_OKAY;
4444 
4445  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4446  if( est >= end || ect <= begin )
4447  return SCIP_OKAY;
4448 
4449  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4450  * skip since the overload check will do the job
4451  */
4452  if( est >= begin && ect <= end )
4453  return SCIP_OKAY;
4454 
4455  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4456  * earliest start time
4457  */
4458  if( energy >= demand * (MAX(begin, est) - MIN(end, ect)) )
4459  return SCIP_OKAY;
4460 
4461  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4462  * present; therefore, we need to add the core;
4463  *
4464  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4465  * compute the earliest completion time of the (whole) job
4466  */
4467  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4468 
4469  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4470  *
4471  * @note we can round down the compute duration w.r.t. the available energy
4472  */
4473  newlb = end - energy / demand;
4474 
4475  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4476  * bound (latest start time); meaning it is not possible to schedule the job
4477  */
4478  if( newlb > lct - duration )
4479  {
4480  /* initialize conflict analysis if conflict analysis is applicable */
4482  {
4483  SCIP_Real relaxedbd;
4484 
4485  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4486 
4487  /* it is enough to overshoot the upper bound of the variable by one */
4488  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4489 
4490  /* initialize conflict analysis */
4492 
4493  /* added to upper bound (which was overcut be new lower bound) of the variable */
4494  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4495 
4496  /* analyze the infeasible */
4497  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4498  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4499 
4500  (*initialized) = TRUE;
4501  }
4502 
4503  (*cutoff) = TRUE;
4504  }
4505  else if( newlb > (*bestlb) )
4506  {
4507  INFERINFO inferinfo;
4508 
4509  assert(newlb > begin);
4510 
4511  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4512 
4513  /* construct inference information */
4514  (*inferinfos) = inferInfoToInt(inferinfo);
4515  (*bestlb) = newlb;
4516  }
4517 
4518  return SCIP_OKAY;
4519 }
4520 
4521 /** try to tighten the upper bound of the given variable */
4522 static
4524  SCIP* scip, /**< SCIP data structure */
4525  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4526  int nvars, /**< number of start time variables (activities) */
4527  SCIP_VAR** vars, /**< array of start time variables */
4528  int* durations, /**< array of durations */
4529  int* demands, /**< array of demands */
4530  int capacity, /**< cumulative capacity */
4531  int hmin, /**< left bound of time axis to be considered (including hmin) */
4532  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4533  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4534  int duration, /**< duration of the job */
4535  int demand, /**< demand of the job */
4536  int est, /**< earliest start time of the job */
4537  int lst, /**< latest start time of the flexible part of the job */
4538  int lct, /**< latest completion time of the job */
4539  int begin, /**< begin of the time window under investigation */
4540  int end, /**< end of the time window under investigation */
4541  int energy, /**< available energy for the flexible part of the hob within the time window */
4542  int* bestub, /**< pointer to strope the best upper bound change */
4543  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4544  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4545  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4546  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4547  )
4548 {
4549  int newub;
4550 
4551  assert(begin >= hmin);
4552  assert(end <= hmax);
4553  assert(est < begin);
4554 
4555  /* check if the time-table edge-finding should infer bounds */
4556  if( !conshdlrdata->ttefinfer )
4557  return SCIP_OKAY;
4558 
4559  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4560  if( lst >= end || lct <= begin )
4561  return SCIP_OKAY;
4562 
4563  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4564  * skip since the overload check will do the job
4565  */
4566  if( lst >= begin && lct <= end )
4567  return SCIP_OKAY;
4568 
4569  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4570  if( energy >= demand * (MIN(end, lct) - MAX(begin, lst)) )
4571  return SCIP_OKAY;
4572 
4573  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4574  * present; therefore, we need to add the core;
4575  *
4576  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4577  * latest start of the (whole) job
4578  */
4579  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4580  assert(energy >= 0);
4581 
4582  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4583  *
4584  * @note we can round down the compute duration w.r.t. the available energy
4585  */
4586  assert(demand > 0);
4587  newub = begin - duration + energy / demand;
4588 
4589  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4590  * bound (earliest start time); meaning it is not possible to schedule the job
4591  */
4592  if( newub < est )
4593  {
4594  /* initialize conflict analysis if conflict analysis is applicable */
4596  {
4597  SCIP_Real relaxedbd;
4598 
4599  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4600 
4601  /* it is enough to undershoot the lower bound of the variable by one */
4602  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4603 
4604  /* initialize conflict analysis */
4606 
4607  /* added to lower bound (which was undercut be new upper bound) of the variable */
4608  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4609 
4610  /* analyze the infeasible */
4611  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4612  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4613 
4614  (*initialized) = TRUE;
4615  }
4616 
4617  (*cutoff) = TRUE;
4618  }
4619  else if( newub < (*bestub) )
4620  {
4621  INFERINFO inferinfo;
4622 
4623  assert(newub < begin);
4624 
4625  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4626 
4627  /* construct inference information */
4628  (*inferinfos) = inferInfoToInt(inferinfo);
4629  (*bestub) = newub;
4630  }
4631 
4632  return SCIP_OKAY;
4633 }
4634 
4635 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4636 static
4638  SCIP* scip, /**< SCIP data structure */
4639  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4640  int nvars, /**< number of start time variables (activities) */
4641  SCIP_VAR** vars, /**< array of start time variables */
4642  int* durations, /**< array of durations */
4643  int* demands, /**< array of demands */
4644  int capacity, /**< cumulative capacity */
4645  int hmin, /**< left bound of time axis to be considered (including hmin) */
4646  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4647  int* newlbs, /**< array to buffer new lower bounds */
4648  int* newubs, /**< array to buffer new upper bounds */
4649  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4650  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4651  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4652  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4653  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4654  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4655  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4656  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4657  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4658  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4659  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4660  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4661  )
4662 {
4663  int coreEnergyAfterEnd;
4664  int maxavailable;
4665  int minavailable;
4666  int totalenergy;
4667  int nests;
4668  int est;
4669  int lct;
4670  int start;
4671  int end;
4672  int v;
4673 
4674  est = INT_MAX;
4675  lct = INT_MIN;
4676 
4677  /* compute earliest start and latest completion time of all jobs */
4678  for( v = 0; v < nvars; ++v )
4679  {
4680  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4681  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4682 
4683  est = MIN(est, start);
4684  lct = MAX(lct, end);
4685  }
4686 
4687  /* adjust the effective time horizon */
4688  hmin = MAX(hmin, est);
4689  hmax = MIN(hmax, lct);
4690 
4691  end = hmax + 1;
4692  coreEnergyAfterEnd = -1;
4693 
4694  maxavailable = (hmax - hmin) * capacity;
4695  minavailable = maxavailable;
4696  totalenergy = computeTotalEnergy(durations, demands, nvars);
4697 
4698  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4699  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4700  return SCIP_OKAY;
4701 
4702  nests = nvars;
4703 
4704  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4705  * times define the end of the time interval under investigation
4706  */
4707  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4708  {
4709  int flexenergy;
4710  int minbegin;
4711  int lbenergy;
4712  int lbcand;
4713  int i;
4714 
4715  lct = lcts[v];
4716 
4717  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4718  * infinity capacity is available; hence we skip that
4719  */
4720  if( lct > hmax )
4721  continue;
4722 
4723  /* if the latest completion time is smaller then hmin we have to stop */
4724  if( lct <= hmin )
4725  {
4726  assert(v == 0 || lcts[v-1] <= lcts[v]);
4727  break;
4728  }
4729 
4730  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4731  * induced by end was just analyzed
4732  */
4733  if( lct == end )
4734  continue;
4735 
4736  assert(lct < end);
4737 
4738  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4739  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4740  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4741  */
4742  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4743  {
4744  int freeenergy;
4745 
4746  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4747  assert(coreEnergyAfterEnd >= 0);
4748 
4749  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4750  freeenergy = capacity * (end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4751 
4752  if( freeenergy <= minavailable )
4753  {
4754  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%d>, free energy <%d>)\n", lct, minavailable, freeenergy);
4755  continue;
4756  }
4757  }
4758 
4759  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4760 
4761  end = lct;
4762  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4763 
4764  flexenergy = 0;
4765  minavailable = maxavailable;
4766  minbegin = hmax;
4767  lbcand = -1;
4768  lbenergy = 0;
4769 
4770  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4771  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4772  * wider
4773  */
4774  for( i = nests-1; i >= 0; --i )
4775  {
4776  SCIP_VAR* var;
4777  int freeenergy;
4778  int duration;
4779  int demand;
4780  int begin;
4781  int idx;
4782  int lst;
4783 
4784  idx = perm[i];
4785  assert(idx >= 0);
4786  assert(idx < nvars);
4787  assert(!(*cutoff));
4788 
4789  /* the earliest start time of the job */
4790  est = ests[i];
4791 
4792  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4793  * latest completion times (which define end) are scant in non-increasing order
4794  */
4795  if( end <= est )
4796  {
4797  nests--;
4798  continue;
4799  }
4800 
4801  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4802  * current ending time
4803  */
4804  if( (end - est) * capacity >= totalenergy )
4805  break;
4806 
4807  var = vars[idx];
4808  assert(var != NULL);
4809 
4810  duration = durations[idx];
4811  assert(duration > 0);
4812 
4813  demand = demands[idx];
4814  assert(demand > 0);
4815 
4816  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4817 
4818  /* the latest start time of the free part of the job */
4819  lst = lsts[idx];
4820 
4821  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4822  * investigation; hence the overload check will do the the job
4823  */
4824  assert(est <= minbegin);
4825  if( minavailable < maxavailable && est < minbegin )
4826  {
4827  assert(!(*cutoff));
4828 
4829  /* try to tighten the upper bound */
4830  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4831  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4832  initialized, explanation, cutoff) );
4833 
4834  if( *cutoff )
4835  break;
4836  }
4837 
4838  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4839  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4840 
4841  begin = est;
4842  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4843 
4844  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4845  * free energy
4846  */
4847  if( begin < hmin )
4848  break;
4849 
4850  /* compute the contribution to the flexible energy */
4851  if( lct <= end )
4852  {
4853  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4854  assert(lst >= begin);
4855  assert(flexenergies[idx] >= 0);
4856  flexenergy += flexenergies[idx];
4857  }
4858  else
4859  {
4860  /* the job partly overlaps with the end */
4861  int candenergy;
4862  int energy;
4863 
4864  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4865  * w.r.t. latest start time
4866  *
4867  * @note we need to be aware of the effective horizon
4868  */
4869  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4870  assert(end - lst < duration);
4871  assert(energy >= 0);
4872 
4873  /* adjust the flexible energy of the time interval */
4874  flexenergy += energy;
4875 
4876  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4877  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4878  assert(candenergy >= 0);
4879 
4880  /* check if we found a better candidate */
4881  if( candenergy > lbenergy )
4882  {
4883  lbenergy = candenergy;
4884  lbcand = idx;
4885  }
4886  }
4887 
4888  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4889  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4890 
4891  /* compute the energy which is not used yet */
4892  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4893 
4894  /* check overload */
4895  if( freeenergy < 0 )
4896  {
4897  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4898 
4899  /* initialize conflict analysis if conflict analysis is applicable */
4901  {
4902  /* analyze infeasibilty */
4904 
4905  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4906  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4907  conshdlrdata->usebdwidening, explanation) );
4908 
4909  (*initialized) = TRUE;
4910  }
4911 
4912  (*cutoff) = TRUE;
4913 
4914  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4915  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4916 
4917  break;
4918  }
4919 
4920  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4921  if( lbenergy > 0 && freeenergy < lbenergy )
4922  {
4923  int energy;
4924  int newlb;
4925  int ect;
4926 
4927  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4928  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4929 
4930  /* remove the energy of our job from the ... */
4931  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, end - lsts[lbcand])) * demands[lbcand];
4932 
4933  newlb = end - (int)(energy / demands[lbcand]);
4934 
4935  if( newlb > lst )
4936  {
4937  /* initialize conflict analysis if conflict analysis is applicable */
4939  {
4940  SCIP_Real relaxedbd;
4941 
4942  /* analyze infeasibilty */
4944 
4945  relaxedbd = lst + 1.0;
4946 
4947  /* added to upper bound (which was overcut be new lower bound) of the variable */
4948  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4949 
4950  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4951  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4952  conshdlrdata->usebdwidening, explanation) );
4953 
4954  (*initialized) = TRUE;
4955  }
4956 
4957  (*cutoff) = TRUE;
4958  break;
4959  }
4960  else if( newlb > newlbs[lbcand] )
4961  {
4962  INFERINFO inferinfo;
4963 
4964  /* construct inference information */
4965  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4966 
4967  /* buffer upper bound change */
4968  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4969  newlbs[lbcand] = newlb;
4970  }
4971  }
4972 
4973  /* check if the current interval has a smaller free energy */
4974  if( minavailable > freeenergy )
4975  {
4976  minavailable = freeenergy;
4977  minbegin = begin;
4978  }
4979  assert(minavailable >= 0);
4980  }
4981  }
4982 
4983  return SCIP_OKAY;
4984 }
4985 
4986 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4987 static
4989  SCIP* scip, /**< SCIP data structure */
4990  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4991  int nvars, /**< number of start time variables (activities) */
4992  SCIP_VAR** vars, /**< array of start time variables */
4993  int* durations, /**< array of durations */
4994  int* demands, /**< array of demands */
4995  int capacity, /**< cumulative capacity */
4996  int hmin, /**< left bound of time axis to be considered (including hmin) */
4997  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4998  int* newlbs, /**< array to buffer new lower bounds */
4999  int* newubs, /**< array to buffer new upper bounds */
5000  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5001  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5002  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5003  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5004  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5005  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5006  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5007  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5008  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5009  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5010  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5011  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5012  )
5013 {
5014  int coreEnergyAfterStart;
5015  int maxavailable;
5016  int minavailable;
5017  int totalenergy;
5018  int nlcts;
5019  int begin;
5020  int minest;
5021  int maxlct;
5022  int start;
5023  int end;
5024  int v;
5025 
5026  if( *cutoff )
5027  return SCIP_OKAY;
5028 
5029  begin = hmin - 1;
5030 
5031  minest = INT_MAX;
5032  maxlct = INT_MIN;
5033 
5034  /* compute earliest start and latest completion time of all jobs */
5035  for( v = 0; v < nvars; ++v )
5036  {
5037  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5038  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5039 
5040  minest = MIN(minest, start);
5041  maxlct = MAX(maxlct, end);
5042  }
5043 
5044  /* adjust the effective time horizon */
5045  hmin = MAX(hmin, minest);
5046  hmax = MIN(hmax, maxlct);
5047 
5048  maxavailable = (hmax - hmin) * capacity;
5049  totalenergy = computeTotalEnergy(durations, demands, nvars);
5050 
5051  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5052  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5053  return SCIP_OKAY;
5054 
5055  nlcts = 0;
5056 
5057  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5058  * define the start of the time interval under investigation
5059  */
5060  for( v = 0; v < nvars; ++v )
5061  {
5062  int flexenergy;
5063  int minend;
5064  int ubenergy;
5065  int ubcand;
5066  int est;
5067  int i;
5068 
5069  est = ests[v];
5070 
5071  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5072  * infinity capacity is available; hence we skip that
5073  */
5074  if( est < hmin )
5075  continue;
5076 
5077  /* if the earliest start time is larger or equal then hmax we have to stop */
5078  if( est >= hmax )
5079  break;
5080 
5081  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5082  * induced by start was just analyzed
5083  */
5084  if( est == begin )
5085  continue;
5086 
5087  assert(est > begin);
5088 
5089  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5090 
5091  begin = est;
5092  coreEnergyAfterStart = coreEnergyAfterEst[v];
5093 
5094  flexenergy = 0;
5095  minavailable = maxavailable;
5096  minend = hmin;
5097  ubcand = -1;
5098  ubenergy = 0;
5099 
5100  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5101  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5102  */
5103  for( i = nlcts; i < nvars; ++i )
5104  {
5105  SCIP_VAR* var;
5106  int freeenergy;
5107  int duration;
5108  int demand;
5109  int idx;
5110  int lct;
5111  int ect;
5112 
5113  idx = perm[i];
5114  assert(idx >= 0);
5115  assert(idx < nvars);
5116  assert(!(*cutoff));
5117 
5118  /* the earliest start time of the job */
5119  lct = lcts[i];
5120 
5121  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5122  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5123  */
5124  if( lct <= begin )
5125  {
5126  nlcts++;
5127  continue;
5128  }
5129 
5130  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5131  * start with current beginning time
5132  */
5133  if( (lct - begin) * capacity >= totalenergy )
5134  break;
5135 
5136  var = vars[idx];
5137  assert(var != NULL);
5138 
5139  duration = durations[idx];
5140  assert(duration > 0);
5141 
5142  demand = demands[idx];
5143  assert(demand > 0);
5144 
5145  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5146 
5147  /* the earliest completion time of the flexible part of the job */
5148  ect = ects[idx];
5149 
5150  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5151  * investigation; hence the overload check will do the the job
5152  */
5153  assert(lct >= minend);
5154  if( minavailable < maxavailable && lct > minend )
5155  {
5156  assert(!(*cutoff));
5157 
5158  /* try to tighten the upper bound */
5159  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5160  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5161  initialized, explanation, cutoff) );
5162 
5163  if( *cutoff )
5164  return SCIP_OKAY;
5165  }
5166 
5167  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5168  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5169 
5170  end = lct;
5171  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5172 
5173  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5174  * free energy
5175  */
5176  if( end > hmax )
5177  break;
5178 
5179  /* compute the contribution to the flexible energy */
5180  if( est >= begin )
5181  {
5182  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5183  assert(ect <= end);
5184  assert(flexenergies[idx] >= 0);
5185  flexenergy += flexenergies[idx];
5186  }
5187  else
5188  {
5189  /* the job partly overlaps with the end */
5190  int candenergy;
5191  int energy;
5192 
5193  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5194  * w.r.t. latest start time
5195  *
5196  * @note we need to be aware of the effective horizon
5197  */
5198  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5199  assert(ect - begin < duration);
5200  assert(energy >= 0);
5201 
5202  /* adjust the flexible energy of the time interval */
5203  flexenergy += energy;
5204 
5205  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5206  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5207  assert(candenergy >= 0);
5208 
5209  /* check if we found a better candidate */
5210  if( candenergy > ubenergy )
5211  {
5212  ubenergy = candenergy;
5213  ubcand = idx;
5214  }
5215  }
5216 
5217  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5218  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5219 
5220  /* compute the energy which is not used yet */
5221  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5222 
5223  /* check overload */
5224  if( freeenergy < 0 )
5225  {
5226  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5227 
5228  /* initialize conflict analysis if conflict analysis is applicable */
5230  {
5231  /* analyze infeasibilty */
5233 
5234  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5235  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5236  conshdlrdata->usebdwidening, explanation) );
5237 
5238  (*initialized) = TRUE;
5239  }
5240 
5241  (*cutoff) = TRUE;
5242 
5243  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5244  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5245 
5246  return SCIP_OKAY;
5247  }
5248 
5249  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5250  if( ubenergy > 0 && freeenergy < ubenergy )
5251  {
5252  int energy;
5253  int newub;
5254  int lst;
5255 
5256  duration = durations[ubcand];
5257  assert(duration > 0);
5258 
5259  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5260  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5261 
5262  /* remove the energy of our job from the ... */
5263  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, ects[ubcand] - begin)) * demands[ubcand];
5264 
5265  newub = begin - duration + (int)(energy / demands[ubcand]);
5266 
5267  if( newub < ect - duration )
5268  {
5269  /* initialize conflict analysis if conflict analysis is applicable */
5271  {
5272  SCIP_Real relaxedbd;
5273  /* analyze infeasibilty */
5275 
5276  relaxedbd = ect - duration - 1.0;
5277 
5278  /* added to lower bound (which was undercut be new upper bound) of the variable */
5279  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5280 
5281  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5282  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5283  conshdlrdata->usebdwidening, explanation) );
5284 
5285  (*initialized) = TRUE;
5286  }
5287 
5288  (*cutoff) = TRUE;
5289  return SCIP_OKAY;
5290  }
5291  else if( newub < newubs[ubcand] )
5292  {
5293  INFERINFO inferinfo;
5294 
5295  /* construct inference information */
5296  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5297 
5298  /* buffer upper bound change */
5299  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5300  newubs[ubcand] = newub;
5301  }
5302  }
5303 
5304  /* check if the current interval has a smaller free energy */
5305  if( minavailable > freeenergy )
5306  {
5307  minavailable = freeenergy;
5308  minend = end;
5309  }
5310  assert(minavailable >= 0);
5311  }
5312  }
5313 
5314  return SCIP_OKAY;
5315 }
5316 
5317 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5318  * edge-finding
5319  *
5320  * @note The algorithm is based on the following two papers:
5321  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5322  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5323  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5324  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5325  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5326  */
5327 static
5329  SCIP* scip, /**< SCIP data structure */
5330  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5331  SCIP_PROFILE* profile, /**< current core profile */
5332  int nvars, /**< number of start time variables (activities) */
5333  SCIP_VAR** vars, /**< array of start time variables */
5334  int* durations, /**< array of durations */
5335  int* demands, /**< array of demands */
5336  int capacity, /**< cumulative capacity */
5337  int hmin, /**< left bound of time axis to be considered (including hmin) */
5338  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5339  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5340  int* nchgbds, /**< pointer to store the number of bound changes */
5341  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5342  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5343  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5344  )
5345 {
5346  int* coreEnergyAfterEst;
5347  int* coreEnergyAfterLct;
5348  int* flexenergies;
5349  int* permests;
5350  int* permlcts;
5351  int* lcts;
5352  int* ests;
5353  int* ects;
5354  int* lsts;
5355 
5356  int* newlbs;
5357  int* newubs;
5358  int* lbinferinfos;
5359  int* ubinferinfos;
5360 
5361  int v;
5362 
5363  /* check if a cutoff was already detected */
5364  if( (*cutoff) )
5365  return SCIP_OKAY;
5366 
5367  /* check if at least the basic overload checking should be perfomed */
5368  if( !conshdlrdata->ttefcheck )
5369  return SCIP_OKAY;
5370 
5371  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5372 
5373  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5374  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5375  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5376  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5377  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5378  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5379  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5380  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5381  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5382 
5383  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5384  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5385  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5386  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5387 
5388  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5389  for( v = 0; v < nvars; ++v )
5390  {
5391  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5392  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5393  lbinferinfos[v] = 0;
5394  ubinferinfos[v] = 0;
5395  }
5396 
5397  /* collect earliest start times, latest completion time, and free energy contributions */
5398  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5399 
5400  /* sort the earliest start times and latest completion in non-decreasing order */
5401  SCIPsortIntInt(ests, permests, nvars);
5402  SCIPsortIntInt(lcts, permlcts, nvars);
5403 
5404  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5405  * points
5406  */
5407  SCIP_CALL( computeCoreEngeryAfter(scip, profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct) );
5408 
5409  /* propagate the upper bounds and "opportunistically" the lower bounds */
5410  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5411  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5412  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5413 
5414  /* propagate the lower bounds and "opportunistically" the upper bounds */
5415  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5416  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5417  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5418 
5419  /* apply the buffer bound changes */
5420  for( v = 0; v < nvars && !(*cutoff); ++v )
5421  {
5422  SCIP_Bool infeasible;
5423  SCIP_Bool tightened;
5424 
5425  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v], TRUE, &infeasible, &tightened) );
5426 
5427  /* since we change first the lower bound of the variable an infeasibilty should be detected */
5428  assert(!infeasible);
5429 
5430  if( tightened )
5431  {
5432  (*nchgbds)++;
5433 
5434  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5436  }
5437 
5438  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v], TRUE, &infeasible, &tightened) );
5439 
5440  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5441  * bound update can be infeasible
5442  */
5443  if( infeasible )
5444  {
5446  {
5447  INFERINFO inferinfo;
5448  SCIP_VAR* var;
5449  int begin;
5450  int end;
5451 
5452  var = vars[v];
5453  assert(var != NULL);
5454 
5455  /* initialize conflict analysis */
5457 
5458  /* convert int to inference information */
5459  inferinfo = intToInferInfo(ubinferinfos[v]);
5460 
5461  /* collect time window from inference information */
5462  begin = inferInfoGetData1(inferinfo);
5463  end = inferInfoGetData2(inferinfo);
5464  assert(begin < end);
5465 
5466  /* added to lower bound (which was undercut be new upper bound) of the variable */
5467  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5468 
5469  /* analysis the upper bound change */
5470  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5471  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5472  conshdlrdata->usebdwidening, explanation) );
5473 
5474  (*initialized) = TRUE;
5475  }
5476 
5477  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5478  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5479 
5480  (*cutoff) = TRUE;
5481  break;
5482  }
5483 
5484  if( tightened )
5485  {
5486  (*nchgbds)++;
5487 
5488  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5490  }
5491  }
5492 
5493  SCIPfreeBufferArray(scip, &ubinferinfos);
5494  SCIPfreeBufferArray(scip, &lbinferinfos);
5495  SCIPfreeBufferArray(scip, &newubs);
5496  SCIPfreeBufferArray(scip, &newlbs);
5497 
5498  /* free buffer arrays */
5499  SCIPfreeBufferArray(scip, &lsts);
5500  SCIPfreeBufferArray(scip, &ects);
5501  SCIPfreeBufferArray(scip, &ests);
5502  SCIPfreeBufferArray(scip, &lcts);
5503  SCIPfreeBufferArray(scip, &permests);
5504  SCIPfreeBufferArray(scip, &permlcts);
5505  SCIPfreeBufferArray(scip, &flexenergies);
5506  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5507  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5508 
5509  return SCIP_OKAY;
5510 }
5511 
5512 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5513  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5514  * time table propagator
5515  */
5516 static
5518  SCIP* scip, /**< SCIP data structure */
5519  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5520  SCIP_PROFILE* profile, /**< core profile */
5521  int nvars, /**< number of start time variables (activities) */
5522  SCIP_VAR** vars, /**< array of start time variables */
5523  int* durations, /**< array of durations */
5524  int* demands, /**< array of demands */
5525  int capacity, /**< cumulative capacity */
5526  int hmin, /**< left bound of time axis to be considered (including hmin) */
5527  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5528  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5529  int* nchgbds, /**< pointer to store the number of bound changes */
5530  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5531  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5532  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5533  )
5534 {
5535  SCIP_Bool infeasible;
5536  int v;
5537 
5538  assert(scip != NULL);
5539  assert(nvars > 0);
5540  assert(cons != NULL);
5541  assert(cutoff != NULL);
5542 
5543  /* check if already a cutoff was detected */
5544  if( (*cutoff) )
5545  return SCIP_OKAY;
5546 
5547  /* check if the time tabling should infer bounds */
5548  if( !conshdlrdata->ttinfer )
5549  return SCIP_OKAY;
5550 
5551  assert(*initialized == FALSE);
5552 
5553  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5554  SCIPconsGetName(cons), hmin, hmax, capacity);
5555 
5556  infeasible = FALSE;
5557 
5558  /* if core profile is empty; nothing to do */
5559  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5560  return SCIP_OKAY;
5561 
5562  /* start checking each job whether the bounds can be improved */
5563  for( v = 0; v < nvars; ++v )
5564  {
5565  SCIP_VAR* var;
5566  int demand;
5567  int duration;
5568  int begin;
5569  int end;
5570  int est;
5571  int lst;
5572 
5573  var = vars[v];
5574  assert(var != NULL);
5575 
5576  duration = durations[v];
5577  assert(duration > 0);
5578 
5579  /* collect earliest and latest start time */
5580  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5581  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5582 
5583  /* check if the start time variables is already fixed; in that case we can ignore the job */
5584  if( est == lst )
5585  continue;
5586 
5587  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5588  if( lst + duration <= hmin || est >= hmax )
5589  continue;
5590 
5591  /* compute core interval w.r.t. effective time horizon */
5592  begin = MAX(hmin, lst);
5593  end = MIN(hmax, est + duration);
5594 
5595  demand = demands[v];
5596  assert(demand > 0);
5597 
5598  /* if the job has a core, remove it first */
5599  if( begin < end )
5600  {
5601  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5602  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5603 
5604  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5605  }
5606 
5607  /* first try to update the earliest start time */
5608  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5609  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5610 
5611  if( *cutoff )
5612  break;
5613 
5614  /* second try to update the latest start time */
5615  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5616  profile, v, nchgbds) );
5617 
5618  if( *cutoff )
5619  break;
5620 
5621  /* collect the potentially updated earliest and latest start time */
5622  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5623  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5624 
5625  /* compute core interval w.r.t. effective time horizon */
5626  begin = MAX(hmin, lst);
5627  end = MIN(hmax, est + duration);
5628 
5629  /* after updating the bound we might have a new core */
5630  if( begin < end )
5631  {
5632  int pos;
5633 
5634  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5635  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5636 
5637  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5638 
5639  if( infeasible )
5640  {
5641  /* use conflict analysis to analysis the core insertion which was infeasible */
5642  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5643  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5644 
5645  if( explanation != NULL )
5646  explanation[v] = TRUE;
5647 
5648  (*cutoff) = TRUE;
5649 
5650  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5651  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5652 
5653  break;
5654  }
5655  }
5656  }
5657 
5658  return SCIP_OKAY;
5659 }
5660 
5661 
5662 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5663 struct SCIP_NodeData
5664 {
5665  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5666  SCIP_Real key; /**< key which is to insert the corresponding search node */
5667  int est; /**< earliest start time if the node data belongs to a leaf */
5668  int lct; /**< latest completion time if the node data belongs to a leaf */
5669  int demand; /**< demand of the job if the node data belongs to a leaf */
5670  int duration; /**< duration of the job if the node data belongs to a leaf */
5671  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5672  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5673  int enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5674  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5675  int energylambda;
5676  int enveloplambda;
5677  int idx; /**< index of the start time variable in the (global) variable array */
5678  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5679 };
5680 typedef struct SCIP_NodeData SCIP_NODEDATA;
5682 /** creates a node data structure */
5683 static
5685  SCIP* scip, /**< SCIP data structure */
5686  SCIP_NODEDATA** nodedata /**< pointer to store the create node data */
5687  )
5688 {
5689  SCIP_CALL( SCIPallocBuffer(scip, nodedata) );
5690  (*nodedata)->var = NULL;
5691  (*nodedata)->key = SCIP_INVALID;
5692  (*nodedata)->est = INT_MIN;
5693  (*nodedata)->lct = INT_MAX;
5694  (*nodedata)->duration = 0;
5695  (*nodedata)->demand = 0;
5696  (*nodedata)->enveloptheta = -1;
5697  (*nodedata)->energytheta = 0;
5698  (*nodedata)->enveloplambda = -1;
5699  (*nodedata)->energylambda = -1;
5700  (*nodedata)->idx = -1;
5701  (*nodedata)->intheta = TRUE;
5702 
5703  return SCIP_OKAY;
5704 }
5705 
5706 /** frees a node data structure */
5707 static
5708 void freeNodedata(
5709  SCIP* scip, /**< SCIP data structure */
5710  SCIP_NODEDATA** nodedata /**< pointer to store node data which should be freed */
5711  )
5712 {
5713  if( *nodedata != NULL )
5714  {
5715  SCIPfreeBuffer(scip, nodedata);
5716  }
5717 }
5718 
5719 /** update node data structure strating form the given node along the path to the root node */
5720 static
5722  SCIP* scip, /**< SCIP data structure */
5723  SCIP_BTNODE* node /**< search node which inserted */
5724  )
5725 {
5726  SCIP_BTNODE* left;
5727  SCIP_BTNODE* right;
5728  SCIP_NODEDATA* nodedata;
5729  SCIP_NODEDATA* leftdata;
5730  SCIP_NODEDATA* rightdata;
5731 
5732  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5733 
5734  if( SCIPbtnodeIsLeaf(node) )
5735  node = SCIPbtnodeGetParent(node);
5736 
5737  while( node != NULL )
5738  {
5739  /* get node data */
5740  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5741  assert(nodedata != NULL);
5742 
5743  /* collect node data from left node */
5744  left = SCIPbtnodeGetLeftchild(node);
5745  assert(left != NULL);
5746  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5747  assert(leftdata != NULL);
5748 
5749  /* collect node data from right node */
5750  right = SCIPbtnodeGetRightchild(node);
5751  assert(right != NULL);
5752  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5753  assert(rightdata != NULL);
5754 
5755  /* update envelop and energy */
5756  if( leftdata->enveloptheta >= 0 )
5757  {
5758  assert(rightdata->energytheta != -1);
5759  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5760  }
5761  else
5762  nodedata->enveloptheta = rightdata->enveloptheta;
5763 
5764  assert(leftdata->energytheta != -1);
5765  assert(rightdata->energytheta != -1);
5766  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5767 
5768  if( leftdata->enveloplambda >= 0 )
5769  {
5770  assert(rightdata->energytheta != -1);
5771  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5772  }
5773  else
5774  nodedata->enveloplambda = rightdata->enveloplambda;
5775 
5776  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5777  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5778 
5779  SCIPdebugMsg(scip, "node <%p> lambda envelop %d\n", (void*)node, nodedata->enveloplambda);
5780 
5781  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5782  {
5783  assert(rightdata->energytheta != -1);
5784  assert(leftdata->energytheta != -1);
5785  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5786  }
5787  else if( rightdata->energylambda >= 0 )
5788  {
5789  assert(leftdata->energytheta != -1);
5790  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5791  }
5792  else if( leftdata->energylambda >= 0 )
5793  {
5794  assert(rightdata->energytheta != -1);
5795  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5796  }
5797  else
5798  nodedata->energylambda = -1;
5799 
5800  /* go to parent */
5801  node = SCIPbtnodeGetParent(node);
5802  }
5803 
5804  SCIPdebugMsg(scip, "updating done\n");
5805 
5806  return SCIP_OKAY;
5807 }
5808 
5809 /** updates the key of the first parent on the trace which comes from left */
5810 static
5811 void updateKeyOnTrace(
5812  SCIP_BTNODE* node, /**< node to start the trace */
5813  SCIP_Real key /**< update search key */
5814  )
5815 {
5816  assert(node != NULL);
5817 
5818  while( !SCIPbtnodeIsRoot(node) )
5819  {
5820  SCIP_BTNODE* parent;
5821 
5822  parent = SCIPbtnodeGetParent(node);
5823  assert(parent != NULL);
5824 
5825  if( SCIPbtnodeIsLeftchild(node) )
5826  {
5827  SCIP_NODEDATA* nodedata;
5828 
5829  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5830  assert(nodedata != NULL);
5831 
5832  nodedata->key = key;
5833  return;
5834  }
5835 
5836  node = parent;
5837  }
5838 }
5839 
5840 
5841 /** deletes the given node and updates all envelops */
5842 static
5844  SCIP* scip, /**< SCIP data structure */
5845  SCIP_BT* tree, /**< binary tree */
5846  SCIP_BTNODE* node /**< node to be deleted */
5847  )
5848 {
5849  SCIP_BTNODE* parent;
5850  SCIP_BTNODE* grandparent;
5851  SCIP_BTNODE* sibling;
5852 
5853  assert(scip != NULL);
5854  assert(tree != NULL);
5855  assert(node != NULL);
5856 
5857  assert(SCIPbtnodeIsLeaf(node));
5858  assert(!SCIPbtnodeIsRoot(node));
5859 
5860  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5861 
5862  parent = SCIPbtnodeGetParent(node);
5863  assert(parent != NULL);
5864  if( SCIPbtnodeIsLeftchild(node) )
5865  {
5866  sibling = SCIPbtnodeGetRightchild(parent);
5867  SCIPbtnodeSetRightchild(parent, NULL);
5868  }
5869  else
5870  {
5871  sibling = SCIPbtnodeGetLeftchild(parent);
5872  SCIPbtnodeSetLeftchild(parent, NULL);
5873  }
5874  assert(sibling != NULL);
5875 
5876  grandparent = SCIPbtnodeGetParent(parent);
5877 
5878  if( grandparent != NULL )
5879  {
5880  /* reset parent of sibling */
5881  SCIPbtnodeSetParent(sibling, grandparent);
5882 
5883  /* reset child of grandparent to sibling */
5884  if( SCIPbtnodeIsLeftchild(parent) )
5885  {
5886  SCIPbtnodeSetLeftchild(grandparent, sibling);
5887  }
5888  else
5889  {
5890  SCIP_NODEDATA* nodedata;
5891 
5892  assert(SCIPbtnodeIsRightchild(parent));
5893  SCIPbtnodeSetRightchild(grandparent, sibling);
5894 
5895  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5896 
5897  updateKeyOnTrace(grandparent, nodedata->key);
5898  }
5899 
5900  SCIP_CALL( updateEnvelop(scip, grandparent) );
5901  }
5902  else
5903  {
5904  SCIPbtnodeSetParent(sibling, NULL);
5905 
5906  SCIPbtSetRoot(tree, sibling);
5907  }
5908 
5909  SCIPbtnodeFree(tree, &parent);
5910 
5911  return SCIP_OKAY;
5912 }
5913 
5914 /** moves a node form the theta set into the lambda set and updates the envelops */
5915 static
5917  SCIP* scip, /**< SCIP data structure */
5918  SCIP_BT* tree, /**< binary tree */
5919  SCIP_BTNODE* node /**< node to move into the lambda set */
5920  )
5921 {
5922  SCIP_NODEDATA* nodedata;
5923 
5924  assert(scip != NULL);
5925  assert(tree != NULL);
5926  assert(node != NULL);
5927 
5928  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5929  assert(nodedata != NULL);
5930  assert(nodedata->intheta);
5931 
5932  /* move the contributions form the theta set into the lambda set */
5933  assert(nodedata->enveloptheta != -1);
5934  assert(nodedata->energytheta != -1);
5935  assert(nodedata->enveloplambda == -1);
5936  assert(nodedata->energylambda == -1);
5937  nodedata->enveloplambda = nodedata->enveloptheta;
5938  nodedata->energylambda = nodedata->energytheta;
5939 
5940  nodedata->enveloptheta = -1;
5941  nodedata->energytheta = 0;
5942  nodedata->intheta = FALSE;
5943 
5944  /* update the energy and envelop values on trace */
5945  SCIP_CALL( updateEnvelop(scip, node) );
5946 
5947  return SCIP_OKAY;
5948 }
5949 
5950 /** inserts a node into the theta set and update the envelops */
5951 static
5953  SCIP* scip, /**< SCIP data structure */
5954  SCIP_BT* tree, /**< binary tree */
5955  SCIP_BTNODE* node, /**< node to insert */
5956  SCIP_NODEDATA** nodedatas, /**< array of node data */
5957  int* nnodedatas /**< pointer to number of node data */
5958  )
5959 {
5960  /* if the tree is empty the node will be the root node */
5961  if( SCIPbtIsEmpty(tree) )
5962  {
5963  SCIPbtSetRoot(tree, node);
5964  }
5965  else
5966  {
5967  SCIP_NODEDATA* newnodedata;
5968  SCIP_NODEDATA* leafdata;
5969  SCIP_NODEDATA* nodedata;
5970  SCIP_BTNODE* leaf;
5971  SCIP_BTNODE* newnode;
5972  SCIP_BTNODE* parent;
5973 
5974  leaf = SCIPbtGetRoot(tree);
5975  assert(leaf != NULL);
5976 
5977  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5978  assert(leafdata != NULL);
5979 
5980  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5981  assert(nodedata != NULL);
5982  assert(nodedata->intheta);
5983 
5984  /* find the position to insert the node */
5985  while( !SCIPbtnodeIsLeaf(leaf) )
5986  {
5987  if( nodedata->key < leafdata->key )
5988  leaf = SCIPbtnodeGetLeftchild(leaf);
5989  else
5990  leaf = SCIPbtnodeGetRightchild(leaf);
5991 
5992  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5993  assert(leafdata != NULL);
5994  }
5995 
5996  assert(leaf != NULL);
5997  assert(leaf != node);
5998 
5999  /* create node data */
6000  SCIP_CALL( createNodedata(scip, &newnodedata) );
6001 
6002  /* create a new node */
6003  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6004  assert(newnode != NULL);
6005 
6006  /* store node data to be able to delete them latter */
6007  nodedatas[*nnodedatas] = newnodedata;
6008  (*nnodedatas)++;
6009 
6010  parent = SCIPbtnodeGetParent(leaf);
6011 
6012  if( parent != NULL )
6013  {
6014  SCIPbtnodeSetParent(newnode, parent);
6015 
6016  /* check if the node is the left child */
6017  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6018  {
6019  SCIPbtnodeSetLeftchild(parent, newnode);
6020  }
6021  else
6022  {
6023  SCIPbtnodeSetRightchild(parent, newnode);
6024  }
6025  }
6026  else
6027  SCIPbtSetRoot(tree, newnode);
6028 
6029  if( nodedata->key < leafdata->key )
6030  {
6031  /* node is on the left */
6032  SCIPbtnodeSetLeftchild(newnode, node);
6033  SCIPbtnodeSetRightchild(newnode, leaf);
6034  newnodedata->key = nodedata->key;
6035  }
6036  else
6037  {
6038  /* leaf is on the left */
6039  SCIPbtnodeSetLeftchild(newnode, leaf);
6040  SCIPbtnodeSetRightchild(newnode, node);
6041  newnodedata->key = leafdata->key;
6042  }
6043 
6044  SCIPbtnodeSetParent(leaf, newnode);
6045  SCIPbtnodeSetParent(node, newnode);
6046  }
6047 
6048  /* update envelop */
6049  SCIP_CALL( updateEnvelop(scip, node) );
6050 
6051  return SCIP_OKAY;
6052 }
6053 
6054 /** returns the leaf responsible for the lambda energy */
6055 static
6057  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6058  )
6059 {
6060  SCIP_BTNODE* left;
6061  SCIP_BTNODE* right;
6062  SCIP_NODEDATA* nodedata;
6063  SCIP_NODEDATA* leftdata;
6064  SCIP_NODEDATA* rightdata;
6065 
6066  assert(node != NULL);
6067 
6068  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6069  assert(nodedata != NULL);
6070 
6071  /* check if the node is the (responsible) leaf */
6072  if( SCIPbtnodeIsLeaf(node) )
6073  {
6074  assert(!nodedata->intheta);
6075  return node;
6076  }
6077 
6078  left = SCIPbtnodeGetLeftchild(node);
6079  assert(left != NULL);
6080 
6081  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6082  assert(leftdata != NULL);
6083 
6084  right = SCIPbtnodeGetRightchild(node);
6085  assert(right != NULL);
6086 
6087  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6088  assert(rightdata != NULL);
6089 
6090  assert(nodedata->energylambda != -1);
6091  assert(rightdata->energytheta != -1);
6092 
6093  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6095 
6096  assert(leftdata->energytheta != -1);
6097  assert(rightdata->energylambda != -1);
6098  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6099 
6101 }
6102 
6103 /** returns the leaf responsible for the lambda envelop */
6104 static
6106  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6107  )
6108 {
6109  SCIP_BTNODE* left;
6110  SCIP_BTNODE* right;
6111  SCIP_NODEDATA* nodedata;
6112  SCIP_NODEDATA* leftdata;
6113  SCIP_NODEDATA* rightdata;
6114 
6115  assert(node != NULL);
6116 
6117  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6118  assert(nodedata != NULL);
6119 
6120  /* check if the node is the (responsible) leaf */
6121  if( SCIPbtnodeIsLeaf(node) )
6122  {
6123  assert(!nodedata->intheta);
6124  return node;
6125  }
6126 
6127  left = SCIPbtnodeGetLeftchild(node);
6128  assert(left != NULL);
6129 
6130  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6131  assert(leftdata != NULL);
6132 
6133  right = SCIPbtnodeGetRightchild(node);
6134  assert(right != NULL);
6135 
6136  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6137  assert(rightdata != NULL);
6138 
6139  assert(nodedata->enveloplambda != -1);
6140  assert(rightdata->energytheta != -1);
6141 
6142  /* check if the left or right child is the one defining the envelop for the lambda set */
6143  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6145  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6146  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6148 
6149  assert(rightdata->enveloplambda != -1);
6150  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6151 
6153 }
6154 
6155 
6156 /** reports all elements from set theta to generate a conflicting set */
6157 static
6158 void collectThetaSubtree(
6159  SCIP_BTNODE* node, /**< node within a theta subtree */
6160  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6161  int* nelements, /**< pointer to store the number of elements in omegaset */
6162  int* est, /**< pointer to store the earliest start time of the omega set */
6163  int* lct, /**< pointer to store the latest start time of the omega set */
6164  int* energy /**< pointer to store the energy of the omega set */
6165  )
6166 {
6167  SCIP_NODEDATA* nodedata;
6168 
6169  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6170  assert(nodedata != NULL);
6171 
6172  if( !SCIPbtnodeIsLeaf(node) )
6173  {
6174  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6175  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6176  }
6177  else if( nodedata->intheta )
6178  {
6179  assert(nodedata->var != NULL);
6180  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6181 
6182  omegaset[*nelements] = node;
6183  (*est) = MIN(*est, nodedata->est);
6184  (*lct) = MAX(*lct, nodedata->lct);
6185  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6186  (*nelements)++;
6187  }
6188 }
6189 
6190 
6191 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6192 static
6193 void traceThetaEnvelop(
6194  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6195  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6196  int* nelements, /**< pointer to store the number of elements in omegaset */
6197  int* est, /**< pointer to store the earliest start time of the omega set */
6198  int* lct, /**< pointer to store the latest start time of the omega set */
6199  int* energy /**< pointer to store the energy of the omega set */
6200  )
6201 {
6202  assert(node != NULL);
6203 
6204  if( SCIPbtnodeIsLeaf(node) )
6205  {
6206  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6207  }
6208  else
6209  {
6210  SCIP_BTNODE* left;
6211  SCIP_BTNODE* right;
6212  SCIP_NODEDATA* nodedata;
6213  SCIP_NODEDATA* leftdata;
6214  SCIP_NODEDATA* rightdata;
6215 
6216  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6217  assert(nodedata != NULL);
6218 
6219  left = SCIPbtnodeGetLeftchild(node);
6220  assert(left != NULL);
6221 
6222  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6223  assert(leftdata != NULL);
6224 
6225  right = SCIPbtnodeGetRightchild(node);
6226  assert(right != NULL);
6227 
6228  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6229  assert(rightdata != NULL);
6230 
6231  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6232  assert(nodedata != NULL);
6233 
6234  assert(nodedata->enveloptheta != -1);
6235  assert(rightdata->energytheta != -1);
6236 
6237  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6238  {
6239  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6240  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6241  }
6242  else
6243  {
6244  assert(rightdata->enveloptheta != -1);
6245  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6246  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6247  }
6248  }
6249 }
6250 
6251 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6252 static
6253 void traceLambdaEnergy(
6254  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6255  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6256  int* nelements, /**< pointer to store the number of elements in omega set */
6257  int* est, /**< pointer to store the earliest start time of the omega set */
6258  int* lct, /**< pointer to store the latest start time of the omega set */
6259  int* energy /**< pointer to store the energy of the omega set */
6260  )
6261 {
6262  SCIP_BTNODE* left;
6263  SCIP_BTNODE* right;
6264  SCIP_NODEDATA* nodedata;
6265  SCIP_NODEDATA* leftdata;
6266  SCIP_NODEDATA* rightdata;
6267 
6268  assert(node != NULL);
6269 
6270  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6271  assert(nodedata != NULL);
6272 
6273  /* check if the node is a leaf */
6274  if( SCIPbtnodeIsLeaf(node) )
6275  return;
6276 
6277  left = SCIPbtnodeGetLeftchild(node);
6278  assert(left != NULL);
6279 
6280  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6281  assert(leftdata != NULL);
6282 
6283  right = SCIPbtnodeGetRightchild(node);
6284  assert(right != NULL);
6285 
6286  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6287  assert(rightdata != NULL);
6288 
6289  assert(nodedata->energylambda != -1);
6290  assert(rightdata->energytheta != -1);
6291 
6292  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6293  {
6294  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6295  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6296  }
6297  else
6298  {
6299  assert(leftdata->energytheta != -1);
6300  assert(rightdata->energylambda != -1);
6301  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6302 
6303  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6304  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6305  }
6306 }
6307 
6308 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6309 static
6310 void traceLambdaEnvelop(
6311  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6312  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6313  int* nelements, /**< pointer to store the number of elements in omega set */
6314  int* est, /**< pointer to store the earliest start time of the omega set */
6315  int* lct, /**< pointer to store the latest start time of the omega set */
6316  int* energy /**< pointer to store the energy of the omega set */
6317  )
6318 {
6319  SCIP_BTNODE* left;
6320  SCIP_BTNODE* right;
6321  SCIP_NODEDATA* nodedata;
6322  SCIP_NODEDATA* leftdata;
6323  SCIP_NODEDATA* rightdata;
6324 
6325  assert(node != NULL);
6326 
6327  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6328  assert(nodedata != NULL);
6329 
6330  /* check if the node is a leaf */
6331  if( SCIPbtnodeIsLeaf(node) )
6332  {
6333  assert(!nodedata->intheta);
6334  return;
6335  }
6336 
6337  left = SCIPbtnodeGetLeftchild(node);
6338  assert(left != NULL);
6339 
6340  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6341  assert(leftdata != NULL);
6342 
6343  right = SCIPbtnodeGetRightchild(node);
6344  assert(right != NULL);
6345 
6346  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6347  assert(rightdata != NULL);
6348 
6349  assert(nodedata->enveloplambda != -1);
6350  assert(rightdata->energytheta != -1);
6351 
6352  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6353  {
6354  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6355  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6356  }
6357  else
6358  {
6359  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6360  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6361  {
6362  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6363  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6364  }
6365  else
6366  {
6367  assert(rightdata->enveloplambda != -1);
6368  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6369  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6370  }
6371  }
6372 }
6373 
6374 /** compute the energy contribution by job which corresponds to the given leaf */
6375 static
6377  SCIP_BTNODE* node /**< leaf */
6378  )
6379 {
6380  SCIP_NODEDATA* nodedata;
6381  int duration;
6382 
6383  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6384  assert(nodedata != NULL);
6385  assert(nodedata->var != NULL);
6386 
6387  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6388  assert(duration > 0);
6389 
6390  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6392  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6393 
6394  /* return energy which is contributed by the start time variable */
6395  return nodedata->demand * duration;
6396 }
6397 
6398 /** comparison method for two node data w.r.t. the earliest start time */
6399 static
6400 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6402  int est1;
6403  int est2;
6404 
6405  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6406  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6407 
6408  return (est1 - est2);
6409 }
6410 
6411 /** comparison method for two node data w.r.t. the latest completion time */
6412 static
6413 SCIP_DECL_SORTPTRCOMP(compNodedataLct)
6415  int lct1;
6416  int lct2;
6417 
6418  lct1 = ((SCIP_NODEDATA*)elem1)->lct;
6419  lct2 = ((SCIP_NODEDATA*)elem2)->lct;
6420 
6421  return (lct1 - lct2);
6422 }
6423 
6424 
6425 /** an overload was detected; initialized conflict analysis, add an initial reason
6426  *
6427  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6428  */
6429 static
6431  SCIP* scip, /**< SCIP data structure */
6432  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6433  int capacity, /**< cumulative capacity */
6434  int nleaves, /**< number of responsible leaves */
6435  int est, /**< earliest start time of the ...... */
6436  int lct, /**< latest completly time of the .... */
6437  int reportedenergy, /**< energy which already reported */
6438  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6439  int shift, /**< shift applied to all jobs before adding them to the tree */
6440  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6441  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6442  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6443  )
6444 {
6445  int energy;
6446  int j;
6447 
6448  /* do nothing if conflict analysis is not applicable */
6450  return SCIP_OKAY;
6451 
6452  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6453 
6454  /* compute energy of initial time window */
6455  energy = (lct - est) * capacity;
6456 
6457  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6458  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6459 
6460  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6461  * thereby, compute the time window of interest
6462  */
6463  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6464  {
6465  SCIP_NODEDATA* nodedata;
6466 
6467  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6468  assert(nodedata != NULL);
6469 
6470  reportedenergy += computeEnergyContribution(leaves[j]);
6471 
6472  /* adjust energy if the earliest start time decrease */
6473  if( nodedata->est < est )
6474  {
6475  est = nodedata->est;
6476  energy = (lct - est) * capacity;
6477  }
6478  }
6479  assert(reportedenergy > energy);
6480 
6481  SCIPdebugMsg(scip, "time window [%d,%d) available energy %d, required energy %d\n", est, lct, energy, reportedenergy);
6482 
6483  /* initialize conflict analysis */
6485 
6486  /* flip earliest start time and latest completion time */
6487  if( !propest )
6488  {
6489  SCIPswapInts(&est, &lct);
6490 
6491  /* shift earliest start time and latest completion time */
6492  lct = shift - lct;
6493  est = shift - est;
6494  }
6495  else
6496  {
6497  /* shift earliest start time and latest completion time */
6498  lct = lct + shift;
6499  est = est + shift;
6500  }
6501 
6502  nleaves = j;
6503 
6504  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6505  * overloaded
6506  */
6507  for( j = nleaves-1; j >= 0; --j )
6508  {
6509  SCIP_NODEDATA* nodedata;
6510 
6511  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6512  assert(nodedata != NULL);
6513  assert(nodedata->var != NULL);
6514 
6515  /* check if bound widening should be used */
6516  if( usebdwidening )
6517  {
6518  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6519  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6520  }
6521  else
6522  {
6523  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6524  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6525  }
6526 
6527  if( explanation != NULL )
6528  explanation[nodedata->idx] = TRUE;
6529  }
6530 
6531  (*initialized) = TRUE;
6532 
6533  return SCIP_OKAY;
6534 }
6535 
6536 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6537  * responsible interval bounds in *est_omega and *lct_omega
6538  */
6539 static
6540 int computeEstOmegaset(
6541  SCIP* scip, /**< SCIP data structure */
6542  int duration, /**< duration of the job to move */
6543  int demand, /**< demand of the job to move */
6544  int capacity, /**< cumulative capacity */
6545  int est, /**< earliest start time of the omega set */
6546  int lct, /**< latest start time of the omega set */
6547  int energy /**< energy of the omega set */
6548  )
6549 {
6550  int newest;
6551 
6552  newest = 0;
6553 
6554  assert(scip != NULL);
6555 
6556  if( energy > (capacity - demand) * (lct - est) )
6557  {
6558  if( energy + demand * duration > capacity * (lct - est) )
6559  {
6560  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6561  newest += est;
6562  }
6563  }
6564 
6565  return newest;
6566 }
6567 
6568 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6569  *
6570  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6571  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6572  */
6573 static
6575  SCIP* scip, /**< SCIP data structure */
6576  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6577  SCIP_CONS* cons, /**< constraint which is propagated */
6578  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6579  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6580  int capacity, /**< cumulative capacity */
6581  int ncands, /**< number of candidates */
6582  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6583  int shift, /**< shift applied to all jobs before adding them to the tree */
6584  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6585  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6586  int* nchgbds, /**< pointer to store the number of bound changes */
6587  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6588  )
6589 {
6590  SCIP_NODEDATA* rootdata;
6591  int j;
6592 
6593  assert(!SCIPbtIsEmpty(tree));
6594 
6595  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6596  assert(rootdata != NULL);
6597 
6598  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6599  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6600  {
6601  SCIP_NODEDATA* nodedata;
6602 
6603  if( SCIPbtnodeIsRoot(leaves[j]) )
6604  break;
6605 
6606  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6607  assert(nodedata->est != -1);
6608 
6609  /* check if the root lambda envelop exeeds the available capacity */
6610  while( !(*cutoff) && rootdata->enveloplambda > capacity * nodedata->lct )
6611  {
6612  SCIP_BTNODE** omegaset;
6613  SCIP_BTNODE* leaf;
6614  SCIP_NODEDATA* leafdata;
6615  int nelements;
6616  int energy;
6617  int newest;
6618  int est;
6619  int lct;
6620 
6621  assert(!(*cutoff));
6622 
6623  /* find responsible leaf for the lambda envelope */
6625  assert(leaf != NULL);
6626  assert(SCIPbtnodeIsLeaf(leaf));
6627 
6628  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6629  assert(leafdata != NULL);
6630  assert(!leafdata->intheta);
6631  assert(leafdata->duration > 0);
6632  assert(leafdata->est >= 0);
6633 
6634  /* check if the job has to be removed since its latest completion is to large */
6635  if( leafdata->est + leafdata->duration >= nodedata->lct )
6636  {
6637  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6638 
6639  /* the root might changed therefore we need to collect the new root node data */
6640  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6641  assert(rootdata != NULL);
6642 
6643  continue;
6644  }
6645 
6646  /* compute omega set */
6647  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6648 
6649  nelements = 0;
6650  est = INT_MAX;
6651  lct = INT_MIN;
6652  energy = 0;
6653 
6654  /* collect the omega set from theta set */
6655  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6656  assert(nelements > 0);
6657  assert(nelements < ncands);
6658 
6659  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6660 
6661  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6662  if( newest > lct )
6663  {
6664  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6665 
6666  /* analyze over load */
6667  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6668  conshdlrdata->usebdwidening, initialized, explanation) );
6669  (*cutoff) = TRUE;
6670 
6671  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6672  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6673  }
6674  else if( newest > 0 )
6675  {
6676  SCIP_Bool infeasible;
6677  SCIP_Bool tightened;
6678  INFERINFO inferinfo;
6679 
6680  if( propest )
6681  {
6682  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6683  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6684 
6685  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6686  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6687 
6688  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6689  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6690 
6691  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6693  }
6694  else
6695  {
6696  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6697  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6698 
6699  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6700  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6701 
6702  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6703  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6704 
6705  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6707  }
6708 
6709  /* adjust the earliest start time */
6710  if( tightened )
6711  {
6712  leafdata->est = newest;
6713  (*nchgbds)++;
6714  }
6715 
6716  if( infeasible )
6717  {
6718  /* initialize conflict analysis if conflict analysis is applicable */
6720  {
6721  int i;
6722 
6723  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6724 
6726 
6727  /* add lower and upper bound of variable which leads to the infeasibilty */
6728  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6729  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6730 
6731  if( explanation != NULL )
6732  explanation[leafdata->idx] = TRUE;
6733 
6734  /* add lower and upper bound of variable which lead to the infeasibilty */
6735  for( i = 0; i < nelements; ++i )
6736  {
6737  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6738  assert(nodedata != NULL);
6739 
6740  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6741  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6742 
6743  if( explanation != NULL )
6744  explanation[nodedata->idx] = TRUE;
6745  }
6746 
6747  (*initialized) = TRUE;
6748  }
6749 
6750  (*cutoff) = TRUE;
6751 
6752  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6753  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6754  }
6755  }
6756 
6757  /* free omegaset array */
6758  SCIPfreeBufferArray(scip, &omegaset);
6759 
6760  /* delete responsible leaf from lambda */
6761  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6762 
6763  /* the root might changed therefore we need to collect the new root node data */
6764  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6765  assert(rootdata != NULL);
6766  }
6767 
6768  /* move current job j from the theta set into the lambda set */
6769  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6770  }
6771 
6772  return SCIP_OKAY;
6773 }
6774 
6775 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6776  *
6777  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6778  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6779  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6780  */
6781 static
6783  SCIP* scip, /**< SCIP data structure */
6784  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6785  int nvars, /**< number of start time variables (activities) */
6786  SCIP_VAR** vars, /**< array of start time variables */
6787  int* durations, /**< array of durations */
6788  int* demands, /**< array of demands */
6789  int capacity, /**< cumulative capacity */
6790  int hmin, /**< left bound of time axis to be considered (including hmin) */
6791  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6792  SCIP_CONS* cons, /**< constraint which is propagated */
6793  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6794  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6795  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6796  int* nchgbds, /**< pointer to store the number of bound changes */
6797  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6798  )
6799 {
6800  SCIP_NODEDATA** nodedatas;
6801  SCIP_BTNODE** leaves;
6802  SCIP_BT* tree;
6803 
6804  int totalenergy;
6805  int nnodedatas;
6806  int ninsertcands;
6807  int ncands;
6808 
6809  int shift;
6810  int j;
6811 
6812  assert(scip != NULL);
6813  assert(cons != NULL);
6814  assert(initialized != NULL);
6815  assert(cutoff != NULL);
6816  assert(*cutoff == FALSE);
6817 
6818  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6819 
6820  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6821  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6822 
6823  ncands = 0;
6824  totalenergy = 0;
6825 
6826  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6827 
6828  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6829  if( propest )
6830  shift = 0;
6831  else
6832  {
6833  shift = 0;
6834 
6835  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6836  * earliest start time propagation to handle the latest completion times
6837  */
6838  for( j = 0; j < nvars; ++j )
6839  {
6840  int lct;
6841 
6842  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6843  shift = MAX(shift, lct);
6844  }
6845  }
6846 
6847  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6848  * horizon
6849  */
6850  for( j = 0; j < nvars; ++j )
6851  {
6852  SCIP_NODEDATA* nodedata;
6853  SCIP_VAR* var;
6854  int duration;
6855  int leftadjust;
6856  int rightadjust;
6857  int energy;
6858  int est;
6859  int lct;
6860 
6861  var = vars[j];
6862  assert(var != NULL);
6863 
6864  duration = durations[j];
6865  assert(duration > 0);
6866 
6867  leftadjust = 0;
6868  rightadjust = 0;
6869 
6870  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6871  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6872 
6873  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6874  * effective horizon [hmin,hmax)
6875  */
6876  if( conshdlrdata->useadjustedjobs )
6877  {
6878  if( est < hmin )
6879  {
6880  leftadjust = (hmin - est);
6881  est = hmin;
6882  }
6883  if( lct > hmax )
6884  {
6885  rightadjust = (lct - hmax);
6886  lct = hmax;
6887  }
6888 
6889  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6890  * with the effective time horizon
6891  */
6892  if( duration - leftadjust - rightadjust <= 0 )
6893  continue;
6894  }
6895  else if( est < hmin || lct > hmax )
6896  continue;
6897 
6898  energy = demands[j] * (duration - leftadjust - rightadjust);
6899  assert(energy > 0);
6900 
6901  totalenergy += energy;
6902 
6903  /* flip earliest start time and latest completion time */
6904  if( !propest )
6905  {
6906  SCIPswapInts(&est, &lct);
6907 
6908  /* shift earliest start time and latest completion time */
6909  lct = shift - lct;
6910  est = shift - est;
6911  }
6912  else
6913  {
6914  /* shift earliest start time and latest completion time */
6915  lct = lct - shift;
6916  est = est - shift;
6917  }
6918  assert(est < lct);
6919  assert(est >= 0);
6920  assert(lct >= 0);
6921 
6922  /* create search node data */
6923  SCIP_CALL( createNodedata(scip, &nodedata) );
6924 
6925  /* initialize search node data */
6926  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6927  nodedata->key = est + j / (2.0 * nvars);
6928  nodedata->var = var;
6929  nodedata->est = est;
6930  nodedata->lct = lct;
6931  nodedata->demand = demands[j];
6932  nodedata->duration = duration;
6933  nodedata->leftadjust = leftadjust;
6934  nodedata->rightadjust = rightadjust;
6935 
6936  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6937  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6938  * particular time interval [a,b] against the time interval [0,b].
6939  */
6940  nodedata->enveloptheta = capacity * est + energy;
6941  nodedata->energytheta = energy;
6942  nodedata->enveloplambda = -1;
6943  nodedata->energylambda = -1;
6944 
6945  nodedata->idx = j;
6946  nodedata->intheta = TRUE;
6947 
6948  nodedatas[ncands] = nodedata;
6949  ncands++;
6950  }
6951 
6952  nnodedatas = ncands;
6953 
6954  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6955  SCIPsortPtr((void**)nodedatas, compNodedataLct, ncands);
6956 
6957  ninsertcands = 0;
6958 
6959  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6960  * the root envelop detects an overload
6961  */
6962  for( j = 0; j < ncands; ++j )
6963  {
6964  SCIP_BTNODE* leaf;
6965  SCIP_NODEDATA* rootdata;
6966 
6967  /* check if the new job opens a time window which size is so large that it offers more energy than the total
6968  * energy of all candidate jobs. If so we skip that one.
6969  */
6970  if( (nodedatas[j]->lct - nodedatas[j]->est) * capacity >= totalenergy )
6971  {
6972  /* set the earliest start time to minus one to mark that candidate to be not used */
6973  nodedatas[j]->est = -1;
6974  continue;
6975  }
6976 
6977  /* create search node */
6978  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)nodedatas[j]) );
6979 
6980  /* insert new node into the theta set and updete the envelops */
6981  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, &nnodedatas) );
6982  assert(nnodedatas <= 2*nvars);
6983 
6984  /* move the inserted candidates together */
6985  leaves[ninsertcands] = leaf;
6986  ninsertcands++;
6987 
6988  assert(!SCIPbtIsEmpty(tree));
6989  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6990  assert(rootdata != NULL);
6991 
6992  /* check if the theta set envelops exceeds the available capacity */
6993  if( rootdata->enveloptheta > capacity * nodedatas[j]->lct )
6994  {
6995  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[j]->lct, j);
6996  (*cutoff) = TRUE;
6997 
6998  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6999  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7000 
7001  break;
7002  }
7003  }
7004 
7005  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7006  if( *cutoff )
7007  {
7008  int glbenery;
7009  int est;
7010  int lct;
7011 
7012  glbenery = 0;
7013  est = nodedatas[j]->est;
7014  lct = nodedatas[j]->lct;
7015 
7016  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7017  * which led to an overload
7018  */
7019  for( j = j+1; j < ncands; ++j )
7020  {
7021  SCIP_NODEDATA* nodedata;
7022  int duration;
7023  int glbest;
7024  int glblct;
7025 
7026  nodedata = nodedatas[j];
7027  assert(nodedata != NULL);
7028 
7029  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7030 
7031  /* get latest start time */
7032  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7033  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7034 
7035  /* check if parts of the jobs run with the time window defined by the last inserted job */
7036  if( glbest < est )
7037  duration -= (est - glbest);
7038 
7039  if( glblct > lct )
7040  duration -= (glblct - lct);
7041 
7042  if( duration > 0 )
7043  {
7044  glbenery += nodedata->demand * duration;
7045 
7046  if( explanation != NULL )
7047  explanation[nodedata->idx] = TRUE;
7048  }
7049  }
7050 
7051  /* analyze the overload */
7052  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7053  conshdlrdata->usebdwidening, initialized, explanation) );
7054  }
7055  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7056  {
7057  /* if we have more than one job insterted and edge-finding should be performed we do it */
7058  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7059  propest, shift, initialized, explanation, nchgbds, cutoff) );
7060  }
7061 
7062  /* free the search nodes data */
7063  for( j = nnodedatas - 1; j >= 0; --j )
7064  {
7065  freeNodedata(scip, &nodedatas[j]);
7066  }
7067 
7068  /* free theta tree */
7069  SCIPbtFree(&tree);
7070 
7071  /* free buffer arrays */
7072  SCIPfreeBufferArray(scip, &leaves);
7073  SCIPfreeBufferArray(scip, &nodedatas);
7074 
7075  return SCIP_OKAY;
7076 }
7077 
7078 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7079  *
7080  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7081  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7082  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7083  */
7084 static
7086  SCIP* scip, /**< SCIP data structure */
7087  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7088  int nvars, /**< number of start time variables (activities) */
7089  SCIP_VAR** vars, /**< array of start time variables */
7090  int* durations, /**< array of durations */
7091  int* demands, /**< array of demands */
7092  int capacity, /**< cumulative capacity */
7093  int hmin, /**< left bound of time axis to be considered (including hmin) */
7094  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7095  SCIP_CONS* cons, /**< constraint which is propagated */
7096  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7097  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7098  int* nchgbds, /**< pointer to store the number of bound changes */
7099  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7100  )
7101 {
7102  /* check if a cutoff was already detected */
7103  if( (*cutoff) )
7104  return SCIP_OKAY;
7105 
7106  /* check if at least the basic overload checking should be preformed */
7107  if( !conshdlrdata->efcheck )
7108  return SCIP_OKAY;
7109 
7110  /* check for overload, which may result in a cutoff */
7111  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7112  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7113 
7114  /* check if a cutoff was detected */
7115  if( (*cutoff) )
7116  return SCIP_OKAY;
7117 
7118  /* check if bound should be infer */
7119  if( !conshdlrdata->efinfer )
7120  return SCIP_OKAY;
7121 
7122  /* check for overload, which may result in a cutoff */
7123  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7124  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7125 
7126  return SCIP_OKAY;
7127 }
7128 
7129 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7130  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7131  * event points
7132  */
7133 static
7135  SCIP* scip, /**< SCIP data structure */
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_Bool* redundant /**< pointer to store whether this constraint is redundant */
7144  )
7145 {
7146  SCIP_VAR* var;
7147  int* starttimes; /* stores when each job is starting */
7148  int* endtimes; /* stores when each job ends */
7149  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7150  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7151 
7152  int lb;
7153  int ub;
7154  int freecapacity; /* remaining capacity */
7155  int curtime; /* point in time which we are just checking */
7156  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7157  int njobs;
7158  int j;
7159 
7160  assert(scip != NULL);
7161  assert(redundant != NULL);
7162 
7163  (*redundant) = TRUE;
7164 
7165  /* if no activities are associated with this cumulative then this constraint is redundant */
7166  if( nvars == 0 )
7167  return SCIP_OKAY;
7168 
7169  assert(vars != NULL);
7170 
7171  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7172  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7173  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7174  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7175 
7176  njobs = 0;
7177 
7178  /* assign variables, start and endpoints to arrays */
7179  for( j = 0; j < nvars; ++j )
7180  {
7181  assert(durations[j] > 0);
7182  assert(demands[j] > 0);
7183 
7184  var = vars[j];
7185  assert(var != NULL);
7186 
7187  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7188  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7189 
7190  /* check if jobs runs completely outside of the effective time horizon */
7191  if( lb >= hmax || ub + durations[j] <= hmin )
7192  continue;
7193 
7194  starttimes[njobs] = MAX(lb, hmin);
7195  startindices[njobs] = j;
7196 
7197  endtimes[njobs] = MIN(ub + durations[j], hmax);
7198  endindices[njobs] = j;
7199  assert(starttimes[njobs] <= endtimes[njobs]);
7200  njobs++;
7201  }
7202 
7203  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7204  SCIPsortIntInt(starttimes, startindices, njobs);
7205  SCIPsortIntInt(endtimes, endindices, njobs);
7206 
7207  endindex = 0;
7208  freecapacity = capacity;
7209 
7210  /* check each start point of a job whether the capacity is violated or not */
7211  for( j = 0; j < njobs; ++j )
7212  {
7213  curtime = starttimes[j];
7214 
7215  /* stop checking, if time point is above hmax */
7216  if( curtime >= hmax )
7217  break;
7218 
7219  /* subtract all capacity needed up to this point */
7220  freecapacity -= demands[startindices[j]];
7221  while( j+1 < njobs && starttimes[j+1] == curtime )
7222  {
7223  ++j;
7224  freecapacity -= demands[startindices[j]];
7225  }
7226 
7227  /* free all capacity usages of jobs the are no longer running */
7228  while( endtimes[endindex] <= curtime )
7229  {
7230  freecapacity += demands[endindices[endindex]];
7231  ++endindex;
7232  }
7233  assert(freecapacity <= capacity);
7234 
7235  /* check freecapacity to be smaller than zero */
7236  if( freecapacity < 0 && curtime >= hmin )
7237  {
7238  (*redundant) = FALSE;
7239  break;
7240  }
7241  } /*lint --e{850}*/
7242 
7243  /* free all buffer arrays */
7244  SCIPfreeBufferArray(scip, &endindices);
7245  SCIPfreeBufferArray(scip, &startindices);
7246  SCIPfreeBufferArray(scip, &endtimes);
7247  SCIPfreeBufferArray(scip, &starttimes);
7248 
7249  return SCIP_OKAY;
7250 }
7251 
7252 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7253  * completion time
7254  */
7255 static
7257  SCIP* scip, /**< SCIP data structure */
7258  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7259  SCIP_PROFILE* profile, /**< resource profile */
7260  int nvars, /**< number of variables (jobs) */
7261  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7262  int* durations, /**< array containing corresponding durations */
7263  int* demands, /**< array containing corresponding demands */
7264  int capacity, /**< cumulative capacity */
7265  int hmin, /**< left bound of time axis to be considered (including hmin) */
7266  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7267  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7268  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7269  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7270  )
7271 {
7272  int v;
7273 
7274  /* insert all cores */
7275  for( v = 0; v < nvars; ++v )
7276  {
7277  SCIP_VAR* var;
7278  SCIP_Bool infeasible;
7279  int duration;
7280  int demand;
7281  int begin;
7282  int end;
7283  int est;
7284  int lst;
7285  int pos;
7286 
7287  var = vars[v];
7288  assert(var != NULL);
7289  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7290  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7291 
7292  duration = durations[v];
7293  assert(duration > 0);
7294 
7295  demand = demands[v];
7296  assert(demand > 0);
7297 
7298  /* collect earliest and latest start time */
7299  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7300  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7301 
7302  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7303  if( lst + duration <= hmin || est >= hmax )
7304  continue;
7305 
7306  /* compute core interval w.r.t. effective time horizon */
7307  begin = MAX(hmin, lst);
7308  end = MIN(hmax, est + duration);
7309 
7310  /* check if a core exists */
7311  if( begin >= end )
7312  continue;
7313 
7314  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7315  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7316 
7317  /* insert the core into core resource profile (complexity O(log n)) */
7318  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7319 
7320  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7321  if( infeasible )
7322  {
7323  assert(begin <= SCIPprofileGetTime(profile, pos));
7324  assert(end > SCIPprofileGetTime(profile, pos));
7325 
7326  /* use conflict analysis to analysis the core insertion which was infeasible */
7327  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7328  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7329 
7330  if( explanation != NULL )
7331  explanation[v] = TRUE;
7332 
7333  (*cutoff) = TRUE;
7334 
7335  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7336  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7337 
7338  break;
7339  }
7340  }
7341 
7342  return SCIP_OKAY;
7343 }
7344 
7345 /** propagate the cumulative condition */
7346 static
7348  SCIP* scip, /**< SCIP data structure */
7349  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7350  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7351  int nvars, /**< number of start time variables (activities) */
7352  SCIP_VAR** vars, /**< array of start time variables */
7353  int* durations, /**< array of durations */
7354  int* demands, /**< array of demands */
7355  int capacity, /**< cumulative capacity */
7356  int hmin, /**< left bound of time axis to be considered (including hmin) */
7357  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7358  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7359  int* nchgbds, /**< pointer to store the number of bound changes */
7360  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7361  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7362  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7363  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7364  )
7365 {
7366  SCIP_PROFILE* profile;
7367 
7368  SCIP_RETCODE retcode = SCIP_OKAY;
7369 
7370  assert(nchgbds != NULL);
7371  assert(initialized != NULL);
7372  assert(cutoff != NULL);
7373  assert(!(*cutoff));
7374 
7375  /**@todo avoid always sorting the variable array */
7376 
7377  /* check if the constraint is redundant */
7378  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7379 
7380  if( *redundant )
7381  return SCIP_OKAY;
7382 
7383  /* create an empty resource profile for profiling the cores of the jobs */
7384  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7385 
7386  /* create core profile (compulsory parts) */
7387  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7388  initialized, explanation, cutoff), TERMINATE );
7389 
7390  /* propagate the job cores until nothing else can be detected */
7391  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7392  {
7393  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7394  nchgbds, initialized, explanation, cutoff), TERMINATE );
7395  }
7396 
7397  /* run edge finding propagator */
7398  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7399  {
7400  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7401  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7402  }
7403 
7404  /* run time-table edge-finding propagator */
7405  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7406  {
7407  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7408  nchgbds, initialized, explanation, cutoff), TERMINATE );
7409  }
7410  /* free resource profile */
7411 TERMINATE:
7412  SCIPprofileFree(&profile);
7413 
7414  return retcode;
7415 }
7416 
7417 /** propagate the cumulative constraint */
7418 static
7420  SCIP* scip, /**< SCIP data structure */
7421  SCIP_CONS* cons, /**< constraint to propagate */
7422  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7423  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7424  int* nchgbds, /**< pointer to store the number of bound changes */
7425  int* ndelconss, /**< pointer to store the number of deleted constraints */
7426  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7427  )
7428 {
7429  SCIP_CONSDATA* consdata;
7430  SCIP_Bool initialized;
7431  SCIP_Bool redundant;
7432  int oldnchgbds;
7433 
7434  assert(scip != NULL);
7435  assert(cons != NULL);
7436 
7437  consdata = SCIPconsGetData(cons);
7438  assert(consdata != NULL);
7439 
7440  oldnchgbds = *nchgbds;
7441  initialized = FALSE;
7442  redundant = FALSE;
7443 
7444  if( SCIPconsIsDeleted(cons) )
7445  {
7446  assert(SCIPinProbing(scip));
7447  return SCIP_OKAY;
7448  }
7449 
7450  /* if the constraint marked to be propagated, do nothing */
7451  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7452  return SCIP_OKAY;
7453 
7454  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7455  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7456  consdata->hmin, consdata->hmax, cons,
7457  nchgbds, &redundant, &initialized, NULL, cutoff) );
7458 
7459  if( redundant )
7460  {
7461  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7462  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7463 
7464  if( !SCIPinProbing(scip) )
7465  {
7466  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7467  (*ndelconss)++;
7468  }
7469  }
7470  else
7471  {
7472  if( initialized )
7473  {
7474  /* run conflict analysis since it was initialized */
7475  assert(*cutoff == TRUE);
7476  SCIPdebugMsg(scip, "start conflict analysis\n");
7477  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7478  }
7479 
7480  /* if successful, reset age of constraint */
7481  if( *cutoff || *nchgbds > oldnchgbds )
7482  {
7483  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7484  }
7485  else
7486  {
7487  /* mark the constraint to be propagated */
7488  consdata->propagated = TRUE;
7489  }
7490  }
7491 
7492  return SCIP_OKAY;
7493 }
7494 
7495 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7496  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7497  * be realize as domain reduction. Otherwise we do nothing
7498  */
7499 static
7501  SCIP* scip, /**< SCIP data structure */
7502  SCIP_VAR** vars, /**< problem variables */
7503  int nvars, /**< number of problem variables */
7504  int probingpos, /**< variable number to apply probing on */
7505  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7506  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7507  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7508  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7509  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7510  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7511  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7512  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7513  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7514  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7515  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7516  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7517  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7518  )
7519 {
7520  SCIP_VAR* var;
7521  SCIP_Bool tightened;
7522 
7523  assert(probingpos >= 0);
7524  assert(probingpos < nvars);
7525  assert(success != NULL);
7526  assert(cutoff != NULL);
7527 
7528  var = vars[probingpos];
7529  assert(var != NULL);
7530  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7531  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7532  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7533  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7534 
7535  (*success) = FALSE;
7536 
7537  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7538  return SCIP_OKAY;
7539 
7540  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7541  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7542  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7543 
7544  if( (*cutoff) )
7545  {
7546  /* note that cutoff may occur if presolving has not been executed fully */
7547  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7548 
7549  if( tightened )
7550  {
7551  (*success) =TRUE;
7552  (*nfixedvars)++;
7553  }
7554 
7555  return SCIP_OKAY;
7556  }
7557 
7558  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7559  * presolving has not been executed fully
7560  */
7561  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7562  {
7563  /* note that cutoff may occur if presolving has not been executed fully */
7564  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7565 
7566  if( tightened )
7567  {
7568  (*success) = TRUE;
7569  (*nfixedvars)++;
7570  }
7571 
7572  return SCIP_OKAY;
7573  }
7574 
7575  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7576  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7577  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7578 
7579  if( (*cutoff) )
7580  {
7581  /* note that cutoff may occur if presolving has not been executed fully */
7582  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7583 
7584  if( tightened )
7585  {
7586  (*success) =TRUE;
7587  (*nfixedvars)++;
7588  }
7589 
7590  return SCIP_OKAY;
7591  }
7592 
7593  return SCIP_OKAY;
7594 }
7595 
7596 /** is it possible, to round variable down w.r.t. objective function */
7597 static
7599  SCIP* scip, /**< SCIP data structure */
7600  SCIP_VAR* var, /**< problem variable */
7601  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7602  )
7603 {
7604  SCIP_Real objval;
7605  int scalar;
7606 
7607  assert(roundable != NULL);
7608 
7609  *roundable = TRUE;
7610 
7611  /* a fixed variable can be definition always be safely rounded */
7613  return SCIP_OKAY;
7614 
7615  /* in case the variable is not active we need to check the object coefficient of the active variable */
7616  if( !SCIPvarIsActive(var) )
7617  {
7618  SCIP_VAR* actvar;
7619  int constant;
7620 
7621  actvar = var;
7622 
7623  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7624  assert(scalar != 0);
7625 
7626  objval = scalar * SCIPvarGetObj(actvar);
7627  }
7628  else
7629  {
7630  scalar = 1;
7631  objval = SCIPvarGetObj(var);
7632  }
7633 
7634  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7635  * (the transformed problem is always a minimization problem)
7636  *
7637  * @note that we need to check this condition w.r.t. active variable space
7638  */
7639  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7640  *roundable = FALSE;
7641 
7642  return SCIP_OKAY;
7643 }
7644 
7645 /** is it possible, to round variable up w.r.t. objective function */
7646 static
7648  SCIP* scip, /**< SCIP data structure */
7649  SCIP_VAR* var, /**< problem variable */
7650  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7651  )
7652 {
7653  SCIP_Real objval;
7654  int scalar;
7655 
7656  assert(roundable != NULL);
7657 
7658  *roundable = TRUE;
7659 
7660  /* a fixed variable can be definition always be safely rounded */
7662  return SCIP_OKAY;
7663 
7664  /* in case the variable is not active we need to check the object coefficient of the active variable */
7665  if( !SCIPvarIsActive(var) )
7666  {
7667  SCIP_VAR* actvar;
7668  int constant;
7669 
7670  actvar = var;
7671 
7672  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7673  assert(scalar != 0);
7674 
7675  objval = scalar * SCIPvarGetObj(actvar);
7676  }
7677  else
7678  {
7679  scalar = 1;
7680  objval = SCIPvarGetObj(var);
7681  }
7682 
7683  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7684  * (the transformed problem is always a minimization problem)
7685  *
7686  * @note that we need to check this condition w.r.t. active variable space
7687  */
7688  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7689  *roundable = FALSE;
7690 
7691  return SCIP_OKAY;
7692 }
7693 
7694 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7695  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7696  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7697  * the only one locking this variable in the corresponding direction.
7698  */
7699 static
7701  SCIP* scip, /**< SCIP data structure */
7702  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7703  int nconss, /**< number of cumulative constraints */
7704  SCIP_Bool local, /**< use local bounds effective horizon? */
7705  int* alternativelbs, /**< alternative lower bounds */
7706  int* alternativeubs, /**< alternative lower bounds */
7707  int* downlocks, /**< number of constraints with down lock participating by the computation */
7708  int* uplocks /**< number of constraints with up lock participating by the computation */
7709  )
7710 {
7711  int nvars;
7712  int c;
7713  int v;
7714 
7715  for( c = 0; c < nconss; ++c )
7716  {
7717  SCIP_CONSDATA* consdata;
7718  SCIP_CONS* cons;
7719  SCIP_VAR* var;
7720  int hmin;
7721  int hmax;
7722 
7723  cons = conss[c];
7724  assert(cons != NULL);
7725 
7726  /* ignore constraints which are already deletet and those which are not check constraints */
7727  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7728  continue;
7729 
7730  consdata = SCIPconsGetData(cons);
7731  assert(consdata != NULL);
7732  assert(consdata->nvars > 1);
7733 
7734  /* compute the hmin and hmax */
7735  if( local )
7736  {
7737  SCIP_PROFILE* profile;
7738  SCIP_RETCODE retcode;
7739 
7740  /* create empty resource profile with infinity resource capacity */
7741  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7742 
7743  /* create worst case resource profile */
7744  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7745 
7746  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7747  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7748 
7749  /* free worst case profile */
7750  SCIPprofileFree(&profile);
7751 
7752  if( retcode != SCIP_OKAY )
7753  return retcode;
7754  }
7755  else
7756  {
7757  hmin = consdata->hmin;
7758  hmax = consdata->hmax;
7759  }
7760 
7761  consdata = SCIPconsGetData(cons);
7762  assert(consdata != NULL);
7763 
7764  nvars = consdata->nvars;
7765 
7766  for( v = 0; v < nvars; ++v )
7767  {
7768  int scalar;
7769  int constant;
7770  int idx;
7771 
7772  var = consdata->vars[v];
7773  assert(var != NULL);
7774 
7775  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7776  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7777 
7778  /* ignore variable locally fixed variables */
7779  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7780  continue;
7781 
7782  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7783  idx = SCIPvarGetProbindex(var);
7784  assert(idx >= 0);
7785 
7786  /* first check lower bound fixing */
7787  if( consdata->downlocks[v] )
7788  {
7789  int ect;
7790  int est;
7791 
7792  /* the variable has a down locked */
7793  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7794  ect = est + consdata->durations[v];
7795 
7796  if( ect <= hmin || hmin >= hmax )
7797  downlocks[idx]++;
7798  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7799  {
7800  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7801  downlocks[idx]++;
7802  }
7803  }
7804 
7805  /* second check upper bound fixing */
7806  if( consdata->uplocks[v] )
7807  {
7808  int duration;
7809  int lct;
7810  int lst;
7811 
7812  duration = consdata->durations[v];
7813 
7814  /* the variable has a up lock locked */
7815  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7816  lct = lst + duration;
7817 
7818  if( lst >= hmax || hmin >= hmax )
7819  uplocks[idx]++;
7820  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7821  {
7822  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7823  uplocks[idx]++;
7824  }
7825  }
7826  }
7827  }
7828 
7829  return SCIP_OKAY;
7830 }
7831 
7832 /** apply all fixings which are given by the alternative bounds */
7833 static
7835  SCIP* scip, /**< SCIP data structure */
7836  SCIP_VAR** vars, /**< array of active variables */
7837  int nvars, /**< number of active variables */
7838  int* alternativelbs, /**< alternative lower bounds */
7839  int* alternativeubs, /**< alternative lower bounds */
7840  int* downlocks, /**< number of constraints with down lock participating by the computation */
7841  int* uplocks, /**< number of constraints with up lock participating by the computation */
7842  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7843  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7844  )
7845 {
7846  SCIP_Real* downimpllbs;
7847  SCIP_Real* downimplubs;
7848  SCIP_Real* downproplbs;
7849  SCIP_Real* downpropubs;
7850  SCIP_Real* upimpllbs;
7851  SCIP_Real* upimplubs;
7852  SCIP_Real* upproplbs;
7853  SCIP_Real* uppropubs;
7854  int v;
7855 
7856  /* get temporary memory for storing probing results */
7857  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7858  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7859  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7860  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7861  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7862  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7863  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7864  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7865 
7866  for( v = 0; v < nvars; ++v )
7867  {
7868  SCIP_VAR* var;
7869  SCIP_Bool infeasible;
7870  SCIP_Bool fixed;
7871  SCIP_Bool roundable;
7872  int ub;
7873  int lb;
7874 
7875  var = vars[v];
7876  assert(var != NULL);
7877 
7878  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7879  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7880 
7881  /* ignore fixed variables */
7882  if( ub - lb <= 0 )
7883  continue;
7884 
7885  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7886  {
7887  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7888 
7889  if( roundable )
7890  {
7891  if( alternativelbs[v] > ub )
7892  {
7893  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7894  assert(!infeasible);
7895  assert(fixed);
7896 
7897  (*nfixedvars)++;
7898 
7899  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7900  * constraints
7901  */
7902  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7903  }
7904  else
7905  {
7906  SCIP_Bool success;
7907 
7908  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7909  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7910  * infeasible we can apply the dual reduction; otherwise we do nothing
7911  */
7912  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7913  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7914  nfixedvars, &success, cutoff) );
7915 
7916  if( success )
7917  {
7918  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7919  }
7920  }
7921  }
7922  }
7923 
7924  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7925  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7926 
7927  /* ignore fixed variables */
7928  if( ub - lb <= 0 )
7929  continue;
7930 
7931  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7932  {
7933  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7934 
7935  if( roundable )
7936  {
7937  if( alternativeubs[v] < lb )
7938  {
7939  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7940  assert(!infeasible);
7941  assert(fixed);
7942 
7943  (*nfixedvars)++;
7944 
7945  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7946  * constraints
7947  */
7948  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7949  }
7950  else
7951  {
7952  SCIP_Bool success;
7953 
7954  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7955  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7956  * infeasible we can apply the dual reduction; otherwise we do nothing
7957  */
7958  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7959  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7960  nfixedvars, &success, cutoff) );
7961 
7962  if( success )
7963  {
7964  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7965  }
7966  }
7967  }
7968  }
7969  }
7970 
7971  /* free temporary memory */
7972  SCIPfreeBufferArray(scip, &uppropubs);
7973  SCIPfreeBufferArray(scip, &upproplbs);
7974  SCIPfreeBufferArray(scip, &upimplubs);
7975  SCIPfreeBufferArray(scip, &upimpllbs);
7976  SCIPfreeBufferArray(scip, &downpropubs);
7977  SCIPfreeBufferArray(scip, &downproplbs);
7978  SCIPfreeBufferArray(scip, &downimplubs);
7979  SCIPfreeBufferArray(scip, &downimpllbs);
7980 
7981  return SCIP_OKAY;
7982 }
7983 
7984 /** propagate all constraints together */
7985 static
7987  SCIP* scip, /**< SCIP data structure */
7988  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7989  SCIP_CONS** conss, /**< all cumulative constraint */
7990  int nconss, /**< number of cumulative constraints */
7991  SCIP_Bool local, /**< use local bounds effective horizon? */
7992  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7993  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7994  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7995  )
7996 { /*lint --e{715}*/
7997  SCIP_VAR** vars;
7998  int* downlocks;
7999  int* uplocks;
8000  int* alternativelbs;
8001  int* alternativeubs;
8002  int oldnfixedvars;
8003  int nvars;
8004  int v;
8005 
8006  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8007  return SCIP_OKAY;
8008 
8009  nvars = SCIPgetNVars(scip);
8010  oldnfixedvars = *nfixedvars;
8011 
8012  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8013  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8014  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8015  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8016  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8017 
8018  /* initialize arrays */
8019  for( v = 0; v < nvars; ++v )
8020  {
8021  downlocks[v] = 0;
8022  uplocks[v] = 0;
8023  alternativelbs[v] = INT_MAX;
8024  alternativeubs[v] = INT_MIN;
8025  }
8026 
8027  /* compute alternative bounds */
8028  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8029 
8030  /* apply fixing which result of the alternative bounds directly */
8031  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8032  nfixedvars, cutoff) );
8033 
8034  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8035  {
8036  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8037  }
8038 
8039  /* free all buffers */
8040  SCIPfreeBufferArray(scip, &alternativeubs);
8041  SCIPfreeBufferArray(scip, &alternativelbs);
8042  SCIPfreeBufferArray(scip, &uplocks);
8043  SCIPfreeBufferArray(scip, &downlocks);
8044  SCIPfreeBufferArray(scip, &vars);
8045 
8046  return SCIP_OKAY;
8047 }
8048 
8049 /**@} */
8050 
8051 /**@name Linear relaxations
8052  *
8053  * @{
8054  */
8055 
8056 /** creates covering cuts for jobs violating resource constraints */
8057 static
8059  SCIP* scip, /**< SCIP data structure */
8060  SCIP_CONS* cons, /**< constraint to be checked */
8061  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8062  int time /**< at this point in time covering constraints are valid */
8063  )
8064 {
8065  SCIP_CONSDATA* consdata;
8066  SCIP_ROW* row;
8067  int* flexibleids;
8068  int* demands;
8069 
8070  char rowname[SCIP_MAXSTRLEN];
8071 
8072  int remainingcap;
8073  int smallcoversize; /* size of a small cover */
8074  int bigcoversize; /* size of a big cover */
8075  int nvars;
8076 
8077  int nflexible;
8078  int sumdemand; /* demand of all jobs up to a certain index */
8079  int j;
8080 
8081  assert(cons != NULL);
8082 
8083  /* get constraint data structure */
8084  consdata = SCIPconsGetData(cons);
8085  assert(consdata != NULL );
8086 
8087  nvars = consdata->nvars;
8088 
8089  /* sort jobs according to demands */
8090  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8091  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8092 
8093  nflexible = 0;
8094  remainingcap = consdata->capacity;
8095 
8096  /* get all jobs intersecting point 'time' with their bounds */
8097  for( j = 0; j < nvars; ++j )
8098  {
8099  int ub;
8100 
8101  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8102 
8103  /* only add jobs to array if they intersect with point 'time' */
8104  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8105  {
8106  /* if job is fixed, capacity has to be decreased */
8107  if( startvalues[j] == ub )
8108  {
8109  remainingcap -= consdata->demands[j];
8110  }
8111  else
8112  {
8113  demands[nflexible] = consdata->demands[j];
8114  flexibleids[nflexible] = j;
8115  ++nflexible;
8116  }
8117  }
8118  }
8119  assert(remainingcap >= 0);
8120 
8121  /* sort demands and job ids */
8122  SCIPsortIntInt(demands, flexibleids, nflexible);
8123 
8124  /*
8125  * version 1:
8126  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8127  * erzeuge cover constraint
8128  *
8129  */
8130 
8131  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8132  sumdemand = 0;
8133  j = 0;
8134 
8135  while( j < nflexible && sumdemand <= remainingcap )
8136  {
8137  sumdemand += demands[j];
8138  j++;
8139  }
8140 
8141  /* j jobs form a conflict, set coversize to 'j - 1' */
8142  bigcoversize = j-1;
8143  assert(sumdemand > remainingcap);
8144  assert(bigcoversize < nflexible);
8145 
8146  /* - create a row for all jobs and their binary variables.
8147  * - at most coversize many binary variables of jobs can be set to one
8148  */
8149 
8150  /* construct row name */
8151  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8152  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8153  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8154  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8155 
8156  for( j = 0; j < nflexible; ++j )
8157  {
8158  SCIP_VAR** binvars;
8159  int* vals;
8160  int nbinvars;
8161  int idx;
8162  int start;
8163  int end;
8164  int lb;
8165  int ub;
8166  int b;
8167 
8168  idx = flexibleids[j];
8169 
8170  /* get and add binvars into var array */
8171  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8172  assert(nbinvars != 0);
8173 
8174  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8175  assert(vals != NULL);
8176 
8177  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8178  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8179 
8180  /* compute start and finishing time */
8181  start = time - consdata->durations[idx] + 1;
8182  end = MIN(time, ub);
8183 
8184  /* add all neccessary binary variables */
8185  for( b = 0; b < nbinvars; ++b )
8186  {
8187  if( vals[b] < start || vals[b] < lb )
8188  continue;
8189 
8190  if( vals[b] > end )
8191  break;
8192 
8193  assert(binvars[b] != NULL);
8194  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8195  }
8196  }
8197 
8198  /* insert and release row */
8199  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8200 
8201  if( consdata->bcoverrowssize == 0 )
8202  {
8203  consdata->bcoverrowssize = 10;
8204  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8205  }
8206  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8207  {
8208  consdata->bcoverrowssize *= 2;
8209  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8210  }
8211 
8212  consdata->bcoverrows[consdata->nbcoverrows] = row;
8213  consdata->nbcoverrows++;
8214 
8215  /*
8216  * version 2:
8217  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8218  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8219  */
8220  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8221  sumdemand = 0;
8222  j = nflexible -1;
8223  while( sumdemand <= remainingcap )
8224  {
8225  assert(j >= 0);
8226  sumdemand += demands[j];
8227  j--;
8228  }
8229 
8230  smallcoversize = nflexible - (j + 1) - 1;
8231  while( j > 0 && demands[j] == demands[nflexible-1] )
8232  --j;
8233 
8234  assert(smallcoversize < nflexible);
8235 
8236  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8237  {
8238  /* construct row name */
8239  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8240  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8241  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8242  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8243 
8244  /* filter binary variables for each unfixed job */
8245  for( j = j + 1; j < nflexible; ++j )
8246  {
8247  SCIP_VAR** binvars;
8248  int* vals;
8249  int nbinvars;
8250  int idx;
8251  int start;
8252  int end;
8253  int lb;
8254  int ub;
8255  int b;
8256 
8257  idx = flexibleids[j];
8258 
8259  /* get and add binvars into var array */
8260  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8261  assert(nbinvars != 0);
8262 
8263  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8264  assert(vals != NULL);
8265 
8266  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8267  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8268 
8269  /* compute start and finishing time */
8270  start = time - consdata->durations[idx] + 1;
8271  end = MIN(time, ub);
8272 
8273  /* add all neccessary binary variables */
8274  for( b = 0; b < nbinvars; ++b )
8275  {
8276  if( vals[b] < start || vals[b] < lb )
8277  continue;
8278 
8279  if( vals[b] > end )
8280  break;
8281 
8282  assert(binvars[b] != NULL);
8283  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8284  }
8285  }
8286 
8287  /* insert and release row */
8288  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8289  if( consdata->scoverrowssize == 0 )
8290  {
8291  consdata->scoverrowssize = 10;
8292  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8293  }
8294  if( consdata->nscoverrows == consdata->scoverrowssize )
8295  {
8296  consdata->scoverrowssize *= 2;
8297  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8298  }
8299 
8300  consdata->scoverrows[consdata->nscoverrows] = row;
8301  consdata->nscoverrows++;
8302  }
8303 
8304  /* free buffer arrays */
8305  SCIPfreeBufferArray(scip, &flexibleids);
8306  SCIPfreeBufferArray(scip, &demands);
8307 
8308  return SCIP_OKAY;
8309 }
8310 
8311 /** method to construct cover cuts for all points in time */
8312 static
8314  SCIP* scip, /**< SCIP data structure */
8315  SCIP_CONS* cons /**< constraint to be separated */
8316  )
8317 {
8318  SCIP_CONSDATA* consdata;
8319 
8320  int* startvalues; /* stores when each job is starting */
8321  int* endvalues; /* stores when each job ends */
8322  int* startvaluessorted; /* stores when each job is starting */
8323  int* endvaluessorted; /* stores when each job ends */
8324  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8325  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8326 
8327  int nvars; /* number of jobs for this constraint */
8328  int freecapacity; /* remaining capacity */
8329  int curtime; /* point in time which we are just checking */
8330  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8331 
8332  int hmin;
8333  int hmax;
8334 
8335  int j;
8336  int t;
8337 
8338  assert(scip != NULL);
8339  assert(cons != NULL);
8340 
8341  consdata = SCIPconsGetData(cons);
8342  assert(consdata != NULL);
8343 
8344  /* if no activities are associated with this resource then this constraint is redundant */
8345  if( consdata->vars == NULL )
8346  return SCIP_OKAY;
8347 
8348  nvars = consdata->nvars;
8349  hmin = consdata->hmin;
8350  hmax = consdata->hmax;
8351 
8352  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8353  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8354  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8355  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8356  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8357  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8358 
8359  /* assign start and endpoints to arrays */
8360  for ( j = 0; j < nvars; ++j )
8361  {
8362  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8363  startvaluessorted[j] = startvalues[j];
8364 
8365  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8366  endvaluessorted[j] = endvalues[j];
8367 
8368  startindices[j] = j;
8369  endindices[j] = j;
8370  }
8371 
8372  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8373  * (and sort the indices in the same way) */
8374  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8375  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8376 
8377  endidx = 0;
8378  freecapacity = consdata->capacity;
8379 
8380  /* check each startpoint of a job whether the capacity is kept or not */
8381  for( j = 0; j < nvars; ++j )
8382  {
8383  curtime = startvaluessorted[j];
8384  if( curtime >= hmax )
8385  break;
8386 
8387  /* subtract all capacity needed up to this point */
8388  freecapacity -= consdata->demands[startindices[j]];
8389 
8390  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8391  {
8392  ++j;
8393  freecapacity -= consdata->demands[startindices[j]];
8394  }
8395 
8396  /* free all capacity usages of jobs the are no longer running */
8397  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8398  {
8399  freecapacity += consdata->demands[endindices[endidx]];
8400  ++endidx;
8401  }
8402 
8403  assert(freecapacity <= consdata->capacity);
8404  assert(endidx <= nvars);
8405 
8406  /* --> endindex - points to the next job which will finish
8407  * j - points to the last job that has been released
8408  */
8409 
8410  /* check freecapacity to be smaller than zero
8411  * then we will add cover constraints to the MIP
8412  */
8413  if( freecapacity < 0 && curtime >= hmin )
8414  {
8415  int nextprofilechange;
8416 
8417  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8418  if( j < nvars-1 )
8419  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8420  else
8421  nextprofilechange = endvaluessorted[endidx];
8422 
8423  nextprofilechange = MIN(nextprofilechange, hmax);
8424 
8425  for( t = curtime; t < nextprofilechange; ++t )
8426  {
8427  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8428 
8429  /* create covering constraint */
8430  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8431  }
8432  } /* end if freecapacity > 0 */
8433  } /*lint --e{850}*/
8434 
8435  consdata->covercuts = TRUE;
8436 
8437  /* free all buffer arrays */
8438  SCIPfreeBufferArray(scip, &endindices);
8439  SCIPfreeBufferArray(scip, &startindices);
8440  SCIPfreeBufferArray(scip, &endvaluessorted);
8441  SCIPfreeBufferArray(scip, &startvaluessorted);
8442  SCIPfreeBufferArray(scip, &endvalues);
8443  SCIPfreeBufferArray(scip, &startvalues);
8444 
8445  return SCIP_OKAY;
8446 }
8447 
8448 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8449  * constraint
8450  */
8451 static
8453  SCIP* scip, /**< SCIP data structure */
8454  SCIP_CONS* cons, /**< constraint to be checked */
8455  int* startindices, /**< permutation with rspect to the start times */
8456  int curtime, /**< current point in time */
8457  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8458  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8459  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8460  )
8461 {
8462  SCIP_CONSDATA* consdata;
8463  SCIP_VAR** binvars;
8464  int* coefs;
8465  int nbinvars;
8466  char name[SCIP_MAXSTRLEN];
8467  int capacity;
8468  int b;
8469 
8470  assert(nstarted > nfinished);
8471 
8472  consdata = SCIPconsGetData(cons);
8473  assert(consdata != NULL);
8474  assert(consdata->nvars > 0);
8475 
8476  capacity = consdata->capacity;
8477  assert(capacity > 0);
8478 
8479  nbinvars = 0;
8480  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8481 
8482  /* construct row name */
8483  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8484 
8485  if( cutsasconss )
8486  {
8487  SCIP_CONS* lincons;
8488 
8489  /* create knapsack constraint for the given time point */
8490  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8491  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8492 
8493  for( b = 0; b < nbinvars; ++b )
8494  {
8495  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8496  }
8497 
8498  /* add and release the new constraint */
8499  SCIP_CALL( SCIPaddCons(scip, lincons) );
8500  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8501  }
8502  else
8503  {
8504  SCIP_ROW* row;
8505 
8506  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8507  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8508 
8509  for( b = 0; b < nbinvars; ++b )
8510  {
8511  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8512  }
8513 
8514  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8515  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8516 
8517  if( consdata->demandrowssize == 0 )
8518  {
8519  consdata->demandrowssize = 10;
8520  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8521  }
8522  if( consdata->ndemandrows == consdata->demandrowssize )
8523  {
8524  consdata->demandrowssize *= 2;
8525  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8526  }
8527 
8528  consdata->demandrows[consdata->ndemandrows] = row;
8529  consdata->ndemandrows++;
8530  }
8531 
8532  SCIPfreeBufferArrayNull(scip, &binvars);
8533  SCIPfreeBufferArrayNull(scip, &coefs);
8534 
8535  return SCIP_OKAY;
8536 }
8537 
8538 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8539  * row
8540  */
8541 static
8543  SCIP* scip, /**< SCIP data structure */
8544  SCIP_CONS* cons, /**< constraint to be checked */
8545  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8546  )
8547 {
8548  SCIP_CONSDATA* consdata;
8549 
8550  int* starttimes; /* stores when each job is starting */
8551  int* endtimes; /* stores when each job ends */
8552  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8553  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8554 
8555  int nvars; /* number of activities for this constraint */
8556  int freecapacity; /* remaining capacity */
8557  int curtime; /* point in time which we are just checking */
8558  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8559 
8560  int hmin;
8561  int hmax;
8562 
8563  int j;
8564 
8565  assert(scip != NULL);
8566  assert(cons != NULL);
8567 
8568  consdata = SCIPconsGetData(cons);
8569  assert(consdata != NULL);
8570 
8571  nvars = consdata->nvars;
8572 
8573  /* if no activities are associated with this cumulative then this constraint is redundant */
8574  if( nvars == 0 )
8575  return SCIP_OKAY;
8576 
8577  assert(consdata->vars != NULL);
8578 
8579  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8580  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8581  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8582  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8583 
8584  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8585  SCIPconsGetName(cons), nvars);
8586 
8587  /* create event point arrays */
8588  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8589  starttimes, endtimes, startindices, endindices, FALSE);
8590 
8591  endindex = 0;
8592  freecapacity = consdata->capacity;
8593  hmin = consdata->hmin;
8594  hmax = consdata->hmax;
8595 
8596  /* check each startpoint of a job whether the capacity is kept or not */
8597  for( j = 0; j < nvars; ++j )
8598  {
8599  curtime = starttimes[j];
8600  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8601 
8602  if( curtime >= hmax )
8603  break;
8604 
8605  /* remove the capacity requirments for all job which start at the curtime */
8606  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8607 
8608  /* add the capacity requirments for all job which end at the curtime */
8609  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8610 
8611  assert(freecapacity <= consdata->capacity);
8612  assert(endindex <= nvars);
8613 
8614  /* endindex - points to the next job which will finish */
8615  /* j - points to the last job that has been released */
8616 
8617  /* if free capacity is smaller than zero, then add rows to the LP */
8618  if( freecapacity < 0 && curtime >= hmin )
8619  {
8620  int nextstarttime;
8621  int t;
8622 
8623  /* step forward until next job is released and see whether capacity constraint is met or not */
8624  if( j < nvars-1 )
8625  nextstarttime = starttimes[j+1];
8626  else
8627  nextstarttime = endtimes[nvars-1];
8628 
8629  nextstarttime = MIN(nextstarttime, hmax);
8630 
8631  /* create capacity restriction row for current event point */
8632  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8633 
8634  /* create for all points in time between the current event point and next start event point a row if the free
8635  * capacity is still smaller than zero */
8636  for( t = curtime+1 ; t < nextstarttime; ++t )
8637  {
8638  /* add the capacity requirments for all job which end at the curtime */
8639  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8640 
8641  if( freecapacity < 0 )
8642  {
8643  /* add constraint */
8644  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8645 
8646  /* create capacity restriction row */
8647  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8648  }
8649  else
8650  break;
8651  }
8652  }
8653  } /*lint --e{850}*/
8654 
8655  /* free all buffer arrays */
8656  SCIPfreeBufferArray(scip, &endindices);
8657  SCIPfreeBufferArray(scip, &startindices);
8658  SCIPfreeBufferArray(scip, &endtimes);
8659  SCIPfreeBufferArray(scip, &starttimes);
8660 
8661  return SCIP_OKAY;
8662 }
8663 
8664 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8665  * capacity is larger than the capacity of the cumulative constraint
8666  * - for each necessary point in time:
8667  *
8668  * sum_j sum_t demand_j * x_{j,t} <= capacity
8669  *
8670  * where x(j,t) is the binary variables of job j at time t
8671  */
8672 static
8674  SCIP* scip, /**< SCIP data structure */
8675  SCIP_CONS* cons, /**< cumulative constraint */
8676  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8677  )
8678 {
8679  SCIP_CONSDATA* consdata;
8680 
8681  consdata = SCIPconsGetData(cons);
8682  assert(consdata != NULL);
8683  assert(consdata->demandrows == NULL);
8684  assert(consdata->ndemandrows == 0);
8685 
8686  /* collect the linking constraints */
8687  if( consdata->linkingconss == NULL )
8688  {
8689  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8690  }
8691 
8692  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8693 
8694  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8695  if( cutsasconss )
8696  {
8697  if( SCIPconsIsInitial(cons) )
8698  {
8699  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8700  }
8701  if( SCIPconsIsSeparated(cons) )
8702  {
8703  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8704  }
8705  if( SCIPconsIsEnforced(cons) )
8706  {
8707  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8708  }
8709  }
8710 
8711  return SCIP_OKAY;
8712 }
8713 
8714 /** adds linear relaxation of cumulative constraint to the LP */
8715 static
8717  SCIP* scip, /**< SCIP data structure */
8718  SCIP_CONS* cons, /**< cumulative constraint */
8719  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8720  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8721  )
8722 {
8723  SCIP_CONSDATA* consdata;
8724  int r;
8725 
8726  consdata = SCIPconsGetData(cons);
8727  assert(consdata != NULL);
8728 
8729  if( consdata->demandrows == NULL )
8730  {
8731  assert(consdata->ndemandrows == 0);
8732 
8733  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8734 
8735  return SCIP_OKAY;
8736  }
8737 
8738  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8739  {
8740  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8741  {
8742  assert(consdata->demandrows[r] != NULL);
8743  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8744  }
8745  }
8746 
8747  return SCIP_OKAY;
8748 }
8749 
8750 /** checks constraint for violation, and adds it as a cut if possible */
8751 static
8753  SCIP* scip, /**< SCIP data structure */
8754  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8755  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8756  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8757  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8758  )
8759 { /*lint --e{715}*/
8760  SCIP_CONSDATA* consdata;
8761  int ncuts;
8762  int r;
8763 
8764  assert(scip != NULL);
8765  assert(cons != NULL);
8766  assert(separated != NULL);
8767  assert(cutoff != NULL);
8768 
8769  *separated = FALSE;
8770  *cutoff = FALSE;
8771 
8772  consdata = SCIPconsGetData(cons);
8773  assert(consdata != NULL);
8774 
8775  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8776 
8777  if( consdata->demandrows == NULL )
8778  {
8779  assert(consdata->ndemandrows == 0);
8780 
8781  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8782 
8783  return SCIP_OKAY;
8784  }
8785 
8786  ncuts = 0;
8787 
8788  /* check each row that is not contained in LP */
8789  for( r = 0; r < consdata->ndemandrows; ++r )
8790  {
8791  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8792  {
8793  SCIP_Real feasibility;
8794 
8795  if( sol != NULL )
8796  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8797  else
8798  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8799 
8800  if( SCIPisFeasNegative(scip, feasibility) )
8801  {
8802  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8803  if ( *cutoff )
8804  {
8805  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8806  return SCIP_OKAY;
8807  }
8808  *separated = TRUE;
8809  ncuts++;
8810  }
8811  }
8812  }
8813 
8814  if( ncuts > 0 )
8815  {
8816  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8817 
8818  /* if successful, reset age of constraint */
8819  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8820  (*separated) = TRUE;
8821  }
8822 
8823  return SCIP_OKAY;
8824 }
8825 
8826 /** checks constraint for violation, and adds it as a cut if possible */
8827 static
8829  SCIP* scip, /**< SCIP data structure */
8830  SCIP_CONS* cons, /**< logic or constraint to be separated */
8831  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8832  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8833  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8834  )
8835 {
8836  SCIP_CONSDATA* consdata;
8837  SCIP_ROW* row;
8838  SCIP_Real minfeasibility;
8839  int r;
8840 
8841  assert(scip != NULL);
8842  assert(cons != NULL);
8843  assert(separated != NULL);
8844  assert(cutoff != NULL);
8845 
8846  *separated = FALSE;
8847  *cutoff = FALSE;
8848 
8849  consdata = SCIPconsGetData(cons);
8850  assert(consdata != NULL);
8851 
8852  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8853 
8854  /* collect the linking constraints */
8855  if( consdata->linkingconss == NULL )
8856  {
8857  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8858  }
8859 
8860  if( !consdata->covercuts )
8861  {
8862  SCIP_CALL( createCoverCuts(scip, cons) );
8863  }
8864 
8865  row = NULL;
8866  minfeasibility = SCIPinfinity(scip);
8867 
8868  /* check each row of small covers that is not contained in LP */
8869  for( r = 0; r < consdata->nscoverrows; ++r )
8870  {
8871  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8872  {
8873  SCIP_Real feasibility;
8874 
8875  assert(consdata->scoverrows[r] != NULL);
8876  if( sol != NULL )
8877  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8878  else
8879  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8880 
8881  if( minfeasibility > feasibility )
8882  {
8883  minfeasibility = feasibility;
8884  row = consdata->scoverrows[r];
8885  }
8886  }
8887  }
8888 
8889  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8890 
8891  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8892  {
8893  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8894  SCIPconsGetName(cons), minfeasibility);
8895 
8896  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8897  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8898  if ( *cutoff )
8899  return SCIP_OKAY;
8900  (*separated) = TRUE;
8901  }
8902 
8903  minfeasibility = SCIPinfinity(scip);
8904  row = NULL;
8905 
8906  /* check each row of small covers that is not contained in LP */
8907  for( r = 0; r < consdata->nbcoverrows; ++r )
8908  {
8909  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8910  {
8911  SCIP_Real feasibility;
8912 
8913  assert(consdata->bcoverrows[r] != NULL);
8914  if( sol != NULL )
8915  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8916  else
8917  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8918 
8919  if( minfeasibility > feasibility )
8920  {
8921  minfeasibility = feasibility;
8922  row = consdata->bcoverrows[r];
8923  }
8924  }
8925  }
8926 
8927  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8928 
8929  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8930  {
8931  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8932  SCIPconsGetName(cons), minfeasibility);
8933 
8934  assert(row != NULL);
8935  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8936  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8937  if ( *cutoff )
8938  return SCIP_OKAY;
8939  (*separated) = TRUE;
8940  }
8941 
8942  return SCIP_OKAY;
8943 }
8944 
8945 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8946 static
8948  SCIP* scip, /**< SCIP data structure */
8949  SCIP_CONS* cons, /**< constraint to be checked */
8950  int* startindices, /**< permutation with rspect to the start times */
8951  int curtime, /**< current point in time */
8952  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8953  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8954  SCIP_Bool lower /**< shall cuts be created due to lower or upper bounds? */
8955  )
8956 {
8957  SCIP_CONSDATA* consdata;
8958  char name[SCIP_MAXSTRLEN];
8959  SCIP_Bool infeasible;
8960  int lhs; /* left hand side of constraint */
8961 
8962  SCIP_VAR** activevars;
8963  SCIP_ROW* row;
8964 
8965  int v;
8966 
8967  assert(nstarted > nfinished);
8968 
8969  consdata = SCIPconsGetData(cons);
8970  assert(consdata != NULL);
8971  assert(consdata->nvars > 0);
8972 
8973  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8974 
8975  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8976 
8977  if( lower )
8978  {
8979  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8980 
8981  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, (SCIP_Real) lhs, SCIPinfinity(scip),
8982  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8983  }
8984  else
8985  {
8986  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8987  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8988  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8989  }
8990 
8991  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8992 
8993  for( v = 0; v < nstarted - nfinished; ++v )
8994  {
8995  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8996  }
8997 
8998  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8999  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9000 
9001  SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
9002  assert( ! infeasible );
9003 
9004  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9005 
9006  /* free buffers */
9007  SCIPfreeBufferArrayNull(scip, &activevars);
9008 
9009  return SCIP_OKAY;
9010 }
9011 
9012 /** checks constraint for violation, and adds it as a cut if possible */
9013 static
9015  SCIP* scip, /**< SCIP data structure */
9016  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9017  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9018  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9019  SCIP_Bool* separated /**< pointer to store TRUE, if a cut was found */
9020  )
9021 {
9022  SCIP_CONSDATA* consdata;
9023 
9024  int* starttimes; /* stores when each job is starting */
9025  int* endtimes; /* stores when each job ends */
9026  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9027  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9028 
9029  int nvars; /* number of activities for this constraint */
9030  int freecapacity; /* remaining capacity */
9031  int curtime; /* point in time which we are just checking */
9032  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9033 
9034  int hmin;
9035  int hmax;
9036  int j;
9037 
9038  assert(scip != NULL);
9039  assert(cons != NULL);
9040 
9041  consdata = SCIPconsGetData(cons);
9042  assert(consdata != NULL);
9043 
9044  nvars = consdata->nvars;
9045 
9046  /* if no activities are associated with this cumulative then this constraint is redundant */
9047  if( nvars <= 1 )
9048  return SCIP_OKAY;
9049 
9050  assert(consdata->vars != NULL);
9051 
9052  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9053  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9054  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9055  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9056 
9057  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9058  SCIPconsGetName(cons), nvars);
9059 
9060  /* create event point arrays */
9061  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9062 
9063  /* now nvars might be smaller than before! */
9064 
9065  endindex = 0;
9066  freecapacity = consdata->capacity;
9067  hmin = consdata->hmin;
9068  hmax = consdata->hmax;
9069 
9070  /* check each startpoint of a job whether the capacity is kept or not */
9071  for( j = 0; j < nvars; ++j )
9072  {
9073  curtime = starttimes[j];
9074 
9075  if( curtime >= hmax )
9076  break;
9077 
9078  /* remove the capacity requirements for all job which start at the curtime */
9079  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9080 
9081  /* add the capacity requirments for all job which end at the curtime */
9082  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9083 
9084  assert(freecapacity <= consdata->capacity);
9085  assert(endindex <= nvars);
9086 
9087  /* endindex - points to the next job which will finish */
9088  /* j - points to the last job that has been released */
9089 
9090  /* if free capacity is smaller than zero, then add rows to the LP */
9091  if( freecapacity < 0 && curtime >= hmin)
9092  {
9093  /* create capacity restriction row for current event point */
9094  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower) );
9095  *separated = TRUE;
9096  }
9097  } /*lint --e{850}*/
9098 
9099  /* free all buffer arrays */
9100  SCIPfreeBufferArray(scip, &endindices);
9101  SCIPfreeBufferArray(scip, &startindices);
9102  SCIPfreeBufferArray(scip, &endtimes);
9103  SCIPfreeBufferArray(scip, &starttimes);
9104 
9105  return SCIP_OKAY;
9106 }
9107 
9108 /**@} */
9109 
9110 
9111 /**@name Presolving
9112  *
9113  * @{
9114  */
9115 
9116 #ifndef NDEBUG
9117 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9118  * correct
9119  */
9120 static
9122  SCIP* scip, /**< SCIP data structure */
9123  SCIP_CONS* cons /**< constraint to be checked */
9124  )
9125 {
9126  SCIP_CONSDATA* consdata;
9127  int capacity;
9128  int nvars;
9129  int j;
9130 
9131  assert(scip != NULL);
9132  assert(cons != NULL);
9133 
9134  consdata = SCIPconsGetData(cons);
9135  assert(consdata != NULL);
9136 
9137  nvars = consdata->nvars;
9138 
9139  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9140  if( nvars <= 1 )
9141  return TRUE;
9142 
9143  assert(consdata->vars != NULL);
9144  capacity = consdata->capacity;
9145 
9146  /* check each activity: if demand is larger than capacity the problem is infeasible */
9147  for ( j = 0; j < nvars; ++j )
9148  {
9149  if( consdata->demands[j] > capacity )
9150  return FALSE;
9151  }
9152 
9153  return TRUE;
9154 }
9155 #endif
9156 
9157 /** delete constraint if it consists of at most one job
9158  *
9159  * @todo this method needs to be adjusted w.r.t. effective horizon
9160  */
9161 static
9163  SCIP* scip, /**< SCIP data structure */
9164  SCIP_CONS* cons, /**< constraint to propagate */
9165  int* ndelconss, /**< pointer to store the number of deleted constraints */
9166  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9167  )
9168 {
9169  SCIP_CONSDATA* consdata;
9170 
9171  assert(scip != NULL);
9172  assert(cons != NULL);
9173 
9174  consdata = SCIPconsGetData(cons);
9175  assert(consdata != NULL);
9176 
9177  if( consdata->nvars == 0 )
9178  {
9179  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9180 
9181  SCIP_CALL( SCIPdelCons(scip, cons) );
9182  (*ndelconss)++;
9183  }
9184  else if( consdata->nvars == 1 )
9185  {
9186  if( consdata->demands[0] > consdata->capacity )
9187  (*cutoff) = TRUE;
9188  else
9189  {
9190  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9191 
9192  SCIP_CALL( SCIPdelCons(scip, cons) );
9193  (*ndelconss)++;
9194  }
9195  }
9196 
9197  return SCIP_OKAY;
9198 }
9199 
9200 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9201  * this is done in the SCIP_DECL_CONSINITPRE() callback
9202  */
9203 static
9205  SCIP* scip, /**< SCIP data structure */
9206  SCIP_CONS* cons /**< constraint to propagate */
9207  )
9208 {
9209  SCIP_CONSDATA* consdata;
9210  SCIP_VAR* var;
9211  int demand;
9212  int duration;
9213  int hmin;
9214  int hmax;
9215  int est;
9216  int lct;
9217  int j;
9218 
9219  assert(scip != NULL);
9220  assert(cons != NULL);
9221 
9222  consdata = SCIPconsGetData(cons);
9223  assert(consdata != NULL);
9224 
9225  hmin = consdata->hmin;
9226  hmax = consdata->hmax;
9227 
9228  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9229  SCIPconsGetName(cons), hmin, hmax);
9230 
9231  for( j = consdata->nvars-1; j >= 0; --j )
9232  {
9233  var = consdata->vars[j];
9234  demand = consdata->demands[j];
9235  duration = consdata->durations[j];
9236 
9237  /* earliest completion time (ect) and latest start time (lst) */
9238  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9239  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9240 
9241  if( demand == 0 || duration == 0 )
9242  {
9243  /* jobs with zero demand or zero duration can be removed */
9244  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9245  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9246 
9247  /* remove variable form constraint */
9248  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9249  }
9250  else if( est >= hmax || lct <= hmin )
9251  {
9252  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9253  SCIPvarGetName(var), est, lct - duration, duration);
9254 
9255  /* delete variable at the given position */
9256  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9257 
9258  /* for the statistic we count the number of jobs which are irrelevant */
9259  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9260  }
9261  }
9262 
9263  return SCIP_OKAY;
9264 }
9265 
9266 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9267 static
9269  SCIP* scip, /**< SCIP data structure */
9270  SCIP_CONSDATA* consdata, /**< constraint data */
9271  int pos, /**< position of job in the consdata */
9272  int* nchgbds, /**< pointer to store the number of changed bounds */
9273  int* naddconss, /**< pointer to store the number of added constraints */
9274  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9275  )
9276 {
9277  SCIP_VAR* var;
9278  SCIP_Bool tightened;
9279  int duration;
9280  int ect;
9281  int lst;
9282 
9283  assert(scip != NULL);
9284 
9285  /* zero energy jobs should be removed already */
9286  assert(consdata->durations[pos] > 0);
9287  assert(consdata->demands[pos] > 0);
9288 
9289  var = consdata->vars[pos];
9290  assert(var != NULL);
9291  duration = consdata->durations[pos];
9292 
9293  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9294  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9295  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9296 
9297  /* earliest completion time (ect) and latest start time (lst) */
9298  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9299  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9300 
9301  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9302  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9303  return SCIP_OKAY;
9304 
9305  if( ect > consdata->hmin && lst < consdata->hmax )
9306  {
9307  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9308  *cutoff = TRUE;
9309  }
9310  else if( lst < consdata->hmax )
9311  {
9312  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9313  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9314  assert(tightened);
9315  assert(!(*cutoff));
9316  (*nchgbds)++;
9317  }
9318  else if( ect > consdata->hmin )
9319  {
9320  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9321  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9322  assert(tightened);
9323  assert(!(*cutoff));
9324  (*nchgbds)++;
9325  }
9326  else
9327  {
9328  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9329  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9330  *
9331  * (var <= hmin - duration) /\ (var >= hmax)
9332  */
9333  SCIP_CONS* cons;
9334 
9335  SCIP_VAR* vartuple[2];
9336  SCIP_BOUNDTYPE boundtypetuple[2];
9337  SCIP_Real boundtuple[2];
9338 
9339  char name[SCIP_MAXSTRLEN];
9340  int leftbound;
9341  int rightbound;
9342 
9343  leftbound = consdata->hmin - duration;
9344  rightbound = consdata->hmax;
9345 
9346  /* allocate temporary memory for arrays */
9347  vartuple[0] = var;
9348  vartuple[1] = var;
9349  boundtuple[0] = (SCIP_Real)leftbound;
9350  boundtuple[1] = (SCIP_Real)rightbound;
9351  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9352  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9353 
9354  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9355  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9356 
9357  /* create and add bounddisjunction constraint */
9358  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9359  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9360 
9361  SCIPdebugPrintCons(scip, cons, NULL);
9362 
9363  /* add and release the new constraint */
9364  SCIP_CALL( SCIPaddCons(scip, cons) );
9365  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9366  (*naddconss)++;
9367  }
9368 
9369  return SCIP_OKAY;
9370 }
9371 
9372 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9373 static
9375  SCIP* scip, /**< SCIP data structure */
9376  SCIP_CONS* cons, /**< constraint */
9377  int* nchgbds, /**< pointer to store the number of changed bounds */
9378  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9379  int* naddconss, /**< pointer to store the number of added constraints */
9380  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9381  )
9382 {
9383  SCIP_CONSDATA* consdata;
9384  int capacity;
9385  int j;
9386 
9387  consdata = SCIPconsGetData(cons);
9388  assert(consdata != NULL);
9389 
9390  /* if a cutoff was already detected just return */
9391  if( *cutoff )
9392  return SCIP_OKAY;
9393 
9394  capacity = consdata->capacity;
9395 
9396  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9397  {
9398  if( consdata->demands[j] > capacity )
9399  {
9400  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9401 
9402  /* remove variable form constraint */
9403  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9404  (*nchgcoefs)++;
9405  }
9406  }
9407 
9408  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9409 
9410  return SCIP_OKAY;
9411 }
9412 
9413 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9414 static
9416  SCIP* scip, /**< SCIP data structure */
9417  SCIP_VAR* var, /**< integer variable to fix */
9418  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9419  int* nfixedvars /**< pointer to store the number fixed variables */
9420  )
9421 {
9422  SCIP_Bool infeasible;
9423  SCIP_Bool tightened;
9424  SCIP_Bool roundable;
9425 
9426  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9427  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9428  */
9429  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9430  return SCIP_OKAY;
9431 
9432  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9433  * handler is the only one locking that variable up
9434  */
9435  assert(uplock == TRUE || uplock == FALSE);
9436  assert((int)TRUE == 1);
9437  assert((int)FALSE == 0);
9438 
9439  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9440  return SCIP_OKAY;
9441 
9442  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9443 
9444  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9445  * (the transformed problem is always a minimization problem)
9446  */
9447  if( !roundable )
9448  return SCIP_OKAY;
9449 
9450  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9452 
9453  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9454  assert(!infeasible);
9455 
9456  if( tightened )
9457  {
9458  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9459  (*nfixedvars)++;
9460  }
9461 
9462  return SCIP_OKAY;
9463 }
9464 
9465 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9466 static
9468  SCIP* scip, /**< SCIP data structure */
9469  SCIP_VAR* var, /**< integer variable to fix */
9470  SCIP_Bool downlock, /**< has the variable a down lock */
9471  int* nfixedvars /**< pointer to store the number fixed variables */
9472  )
9473 {
9474  SCIP_Bool infeasible;
9475  SCIP_Bool tightened;
9476  SCIP_Bool roundable;
9477 
9478  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9479  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9480  */
9481  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9482  return SCIP_OKAY;
9483 
9484  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9485  * handler is the only one locking that variable down
9486  */
9487  assert(downlock == TRUE || downlock == FALSE);
9488  assert((int)TRUE == 1);
9489  assert((int)FALSE == 0);
9490 
9491  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9492  return SCIP_OKAY;
9493 
9494  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9495 
9496  /* is it possible, to round variable down w.r.t. objective function? */
9497  if( !roundable )
9498  return SCIP_OKAY;
9499 
9500  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9501  assert(!infeasible);
9502 
9503  if( tightened )
9504  {
9505  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9506  (*nfixedvars)++;
9507  }
9508 
9509  return SCIP_OKAY;
9510 }
9511 
9512 /** normalize cumulative condition */
9513 static
9515  SCIP* scip, /**< SCIP data structure */
9516  int nvars, /**< number of start time variables (activities) */
9517  SCIP_VAR** vars, /**< array of start time variables */
9518  int* durations, /**< array of durations */
9519  int* demands, /**< array of demands */
9520  int* capacity, /**< pointer to store the changed cumulative capacity */
9521  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9522  int* nchgsides /**< pointer to count number of side changes */
9523  )
9524 { /*lint --e{715}*/
9525  SCIP_Longint gcd;
9526  int mindemand1;
9527  int mindemand2;
9528  int v;
9529 
9530  if( *capacity == 1 || nvars <= 1 )
9531  return SCIP_OKAY;
9532 
9533  assert(demands[nvars-1] <= *capacity);
9534  assert(demands[nvars-2] <= *capacity);
9535 
9536  gcd = (SCIP_Longint)demands[nvars-1];
9537  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9538  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9539 
9540  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9541  {
9542  assert(mindemand1 <= mindemand2);
9543  assert(demands[v] <= *capacity);
9544 
9545  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9546 
9547  if( mindemand1 > demands[v] )
9548  {
9549  mindemand2 = mindemand1;
9550  mindemand1 = demands[v];
9551  }
9552  else if( mindemand2 > demands[v] )
9553  mindemand2 = demands[v];
9554  }
9555 
9556  if( mindemand1 + mindemand2 > *capacity )
9557  {
9558  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9559 
9560  for( v = 0; v < nvars; ++v )
9561  demands[v] = 1;
9562 
9563  (*capacity) = 1;
9564 
9565  (*nchgcoefs) += nvars;
9566  (*nchgsides)++;
9567  }
9568  else if( gcd >= 2 )
9569  {
9570  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9571 
9572  for( v = 0; v < nvars; ++v )
9573  demands[v] /= gcd;
9574 
9575  (*capacity) /= gcd;
9576 
9577  (*nchgcoefs) += nvars;
9578  (*nchgsides)++;
9579  }
9580 
9581  return SCIP_OKAY;
9582 }
9583 
9584 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9585  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9586  * capacity since in that case none of the jobs can run in parallel
9587  */
9588 static
9590  SCIP* scip, /**< SCIP data structure */
9591  SCIP_CONS* cons, /**< cumulative constraint */
9592  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9593  int* nchgsides /**< pointer to count number of side changes */
9594  )
9595 {
9596  SCIP_CONSDATA* consdata;
9597  int capacity;
9598 
9599  assert(nchgcoefs != NULL);
9600  assert(nchgsides != NULL);
9601  assert(!SCIPconsIsModifiable(cons));
9602 
9603  consdata = SCIPconsGetData(cons);
9604  assert(consdata != NULL);
9605 
9606  if( consdata->normalized )
9607  return SCIP_OKAY;
9608 
9609  capacity = consdata->capacity;
9610 
9611  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9612 
9613  SCIP_CALL( normalizeCumulativeCondition(scip, consdata->nvars, consdata->vars, consdata->durations,
9614  consdata->demands, &consdata->capacity, nchgcoefs, nchgsides) );
9615 
9616  consdata->normalized = TRUE;
9617 
9618  if( capacity > consdata->capacity )
9619  consdata->varbounds = FALSE;
9620 
9621  return SCIP_OKAY;
9622 }
9623 
9624 /** computes for the given cumulative condition the effective horizon */
9625 static
9627  SCIP* scip, /**< SCIP data structure */
9628  int nvars, /**< number of variables (jobs) */
9629  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9630  int* durations, /**< array containing corresponding durations */
9631  int* demands, /**< array containing corresponding demands */
9632  int capacity, /**< available cumulative capacity */
9633  int* hmin, /**< pointer to store the left bound of the effective horizon */
9634  int* hmax, /**< pointer to store the right bound of the effective horizon */
9635  int* split /**< point were the cumulative condition can be split */
9636  )
9637 {
9638  SCIP_PROFILE* profile;
9639 
9640  /* create empty resource profile with infinity resource capacity */
9641  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9642 
9643  /* create worst case resource profile */
9644  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9645 
9646  /* print resource profile in if SCIP_DEBUG is defined */
9647  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9648 
9649  /* computes the first time point where the resource capacity can be violated */
9650  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9651 
9652  /* computes the first time point where the resource capacity is satisfied for sure */
9653  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9654 
9655  (*split) = (*hmax);
9656 
9657  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9658  {
9659  int* timepoints;
9660  int* loads;
9661  int ntimepoints;
9662  int t;
9663 
9664  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9665  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9666  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9667  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9668  * explain the certain "old" bound changes
9669  */
9670 
9671  /* search for time points */
9672  ntimepoints = SCIPprofileGetNTimepoints(profile);
9673  timepoints = SCIPprofileGetTimepoints(profile);
9674  loads = SCIPprofileGetLoads(profile);
9675 
9676  /* 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 */
9677  for( t = 0; t < ntimepoints; ++t )
9678  {
9679  /* ignore all time points before the effective horizon */
9680  if( timepoints[t] <= *hmin )
9681  continue;
9682 
9683  /* ignore all time points after the effective horizon */
9684  if( timepoints[t] >= *hmax )
9685  break;
9686 
9687  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9688  * can split the cumulative constraint into two cumulative constraints
9689  */
9690  if( loads[t] <= capacity )
9691  {
9692  (*split) = timepoints[t];
9693  break;
9694  }
9695  }
9696  }
9697 
9698  /* free worst case profile */
9699  SCIPprofileFree(&profile);
9700 
9701  return SCIP_OKAY;
9702 }
9703 
9704 /** creates and adds a cumulative constraint */
9705 static
9707  SCIP* scip, /**< SCIP data structure */
9708  const char* name, /**< name of constraint */
9709  int nvars, /**< number of variables (jobs) */
9710  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9711  int* durations, /**< array containing corresponding durations */
9712  int* demands, /**< array containing corresponding demands */
9713  int capacity, /**< available cumulative capacity */
9714  int hmin, /**< left bound of time axis to be considered (including hmin) */
9715  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9716  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9717  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9718  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9719  * Usually set to TRUE. */
9720  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9721  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9722  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9723  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9724  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9725  * Usually set to TRUE. */
9726  SCIP_Bool local, /**< is constraint only valid locally?
9727  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9728  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9729  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9730  * adds coefficients to this constraint. */
9731  SCIP_Bool dynamic, /**< is constraint subject to aging?
9732  * Usually set to FALSE. Set to TRUE for own cuts which
9733  * are seperated as constraints. */
9734  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9735  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9736  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9737  * if it may be moved to a more global node?
9738  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9739  )
9740 {
9741  SCIP_CONS* cons;
9742 
9743  /* creates cumulative constraint and adds it to problem */
9744  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9745  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9746 
9747  /* adjust the effective time horizon of the new constraint */
9748  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9749  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9750 
9751  /* add and release new cumulative constraint */
9752  SCIP_CALL( SCIPaddCons(scip, cons) );
9753  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9754 
9755  return SCIP_OKAY;
9756 }
9757 
9758 /** computes the effective horizon and checks if the constraint can be decompsed */
9759 static
9761  SCIP* scip, /**< SCIP data structure */
9762  SCIP_CONS* cons, /**< cumulative constraint */
9763  int* ndelconss, /**< pointer to store the number of deleted constraints */
9764  int* naddconss, /**< pointer to store the number of added constraints */
9765  int* nchgsides /**< pointer to store the number of changed sides */
9766  )
9767 {
9768  SCIP_CONSDATA* consdata;
9769  int hmin;
9770  int hmax;
9771  int split;
9772 
9773  consdata = SCIPconsGetData(cons);
9774  assert(consdata != NULL);
9775 
9776  if( consdata->nvars <= 1 )
9777  return SCIP_OKAY;
9778 
9779  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9780  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9781 
9782  /* check if this time point improves the effective horizon */
9783  if( consdata->hmin < hmin )
9784  {
9785  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9786 
9787  consdata->hmin = hmin;
9788  (*nchgsides)++;
9789  }
9790 
9791  /* check if this time point improves the effective horizon */
9792  if( consdata->hmax > hmax )
9793  {
9794  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9795  consdata->hmax = hmax;
9796  (*nchgsides)++;
9797  }
9798 
9799  /* check if the constraint is redundant */
9800  if( consdata->hmax <= consdata->hmin )
9801  {
9802  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9803  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9804 
9805  SCIP_CALL( SCIPdelCons(scip, cons) );
9806  (*ndelconss)++;
9807  }
9808  else if( consdata->hmin < split && split < consdata->hmax )
9809  {
9810  char name[SCIP_MAXSTRLEN];
9811  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9812 
9813  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9814  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9815 
9816  assert(split < consdata->hmax);
9817 
9818  /* creates cumulative constraint and adds it to problem */
9819  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9820  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9823 
9824  /* adjust the effective time horizon of the constraint */
9825  consdata->hmax = split;
9826 
9827  assert(consdata->hmin < consdata->hmax);
9828 
9829  /* for the statistic we count the number of time we decompose a cumulative constraint */
9831  (*naddconss)++;
9832  }
9833 
9834  return SCIP_OKAY;
9835 }
9836 
9837 
9838 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9839  *
9840  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9841  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9842  *
9843  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9844  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9845  * down-lock of the corresponding start time variable can be removed.
9846  *
9847  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9848  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9849  * negative, than the job can be dual fixed to its earlier start time (est).
9850  *
9851  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9852  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9853  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9854  *
9855  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9856  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9857  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9858  * form variable domain is dual feasible.
9859  *
9860  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9861  * the cumulative condition; The deletion has to be done later.
9862  */
9863 static
9865  SCIP* scip, /**< SCIP data structure */
9866  int nvars, /**< number of start time variables (activities) */
9867  SCIP_VAR** vars, /**< array of start time variables */
9868  int* durations, /**< array of durations */
9869  int hmin, /**< left bound of time axis to be considered (including hmin) */
9870  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9871  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9872  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9873  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9874  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9875  int* nfixedvars, /**< pointer to store the number of fixed variables */
9876  int* nchgsides, /**< pointer to store the number of changed sides */
9877  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9878  )
9879 {
9880  SCIP_Real* downimpllbs;
9881  SCIP_Real* downimplubs;
9882  SCIP_Real* downproplbs;
9883  SCIP_Real* downpropubs;
9884  SCIP_Real* upimpllbs;
9885  SCIP_Real* upimplubs;
9886  SCIP_Real* upproplbs;
9887  SCIP_Real* uppropubs;
9888 
9889  int firstminect;
9890  int secondminect;
9891  int v;
9892 
9893  /* get temporary memory for storing probing results needed for step (4) and (5) */
9894  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9895  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9896  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9897  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9898  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9899  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9900  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9901  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9902 
9903  assert(scip != NULL);
9904  assert(nvars > 1);
9905  assert(cons != NULL);
9906 
9907  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9908 
9909  firstminect = INT_MAX;
9910  secondminect = INT_MAX;
9911 
9912  /* compute the two smallest earlier completion times; which are needed for step (5) */
9913  for( v = 0; v < nvars; ++v )
9914  {
9915  int ect;
9916 
9917  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9918 
9919  if( ect < firstminect )
9920  {
9921  secondminect = firstminect;
9922  firstminect = ect;
9923  }
9924  else if( ect < secondminect )
9925  secondminect = ect;
9926  }
9927 
9928  /* loop over all jobs and check if one of the 5 reductions can be applied */
9929  for( v = 0; v < nvars; ++v )
9930  {
9931  SCIP_VAR* var;
9932  int duration;
9933 
9934  int alternativelb;
9935  int minect;
9936  int est;
9937  int ect;
9938  int lst;
9939  int lct;
9940 
9941  var = vars[v];
9942  assert(var != NULL);
9943 
9944  duration = durations[v];
9945  assert(duration > 0);
9946 
9947  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9948  * time (lct)
9949  */
9950  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9951  ect = est + duration;
9952  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9953  lct = lst + duration;
9954 
9955  /* compute the earliest completion time of all remaining jobs */
9956  if( ect == firstminect )
9957  minect = secondminect;
9958  else
9959  minect = firstminect;
9960 
9961  /* compute potential alternative lower bound (step (4) and (5)) */
9962  alternativelb = MAX(hmin+1, minect);
9963  alternativelb = MIN(alternativelb, hmax);
9964 
9965  if( lct <= hmin )
9966  {
9967  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9968  * cumulative condition
9969  */
9970  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9971  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9972 
9973  /* mark variable to be irrelevant */
9974  irrelevants[v] = TRUE;
9975 
9976  /* for the statistic we count the number of jobs which are irrelevant */
9977  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9978  }
9979  else if( lst <= hmin && SCIPconsIsChecked(cons) )
9980  {
9981  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9982  * so the down lock can be omitted
9983  */
9984 
9985  assert(downlocks != NULL);
9986  assert(uplocks != NULL);
9987 
9988  if( !uplocks[v] )
9989  {
9990  /* the variables has no up lock and we can also remove the down lock;
9991  * => lst <= hmin and ect >= hmax
9992  * => remove job and reduce capacity by the demand of that job
9993  *
9994  * We mark the job to be deletable. The removement together with the capacity reducion is done later
9995  */
9996 
9997  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9998  SCIPvarGetName(var), ect - duration, lst, duration);
9999 
10000  /* mark variable to be irrelevant */
10001  irrelevants[v] = TRUE;
10002 
10003  /* for the statistic we count the number of jobs which always run during the effective horizon */
10005  }
10006 
10007  if( downlocks[v] )
10008  {
10009  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10010  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10011 
10012  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10013  downlocks[v] = FALSE;
10014  (*nchgsides)++;
10015 
10016  /* for the statistic we count the number of removed locks */
10018  }
10019  }
10020  else if( ect <= hmin )
10021  {
10022  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10023  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10024  * removed form the cumulative condition after it was fixed to its earliest start time
10025  */
10026 
10027  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10028  * bound;
10029  */
10030  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10031  {
10032  /* fix integer start time variable if possible to it lower bound */
10033  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10034  }
10035 
10036  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10037  {
10038  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10039  SCIPvarGetName(var), ect - duration, lst, duration);
10040 
10041  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10042  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10043 
10044  /* mark variable to be irrelevant */
10045  irrelevants[v] = TRUE;
10046 
10047  /* for the statistic we count the number of jobs which are dual fixed */
10049  }
10050  }
10051  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10052  {
10053  assert(downlocks != NULL);
10054 
10055  /* check step (4) and (5) */
10056 
10057  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10058  * is in favor of rounding the variable down
10059  */
10060  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10061  {
10062  SCIP_Bool roundable;
10063 
10064  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10065 
10066  if( roundable )
10067  {
10068  if( alternativelb > lst )
10069  {
10070  SCIP_Bool infeasible;
10071  SCIP_Bool fixed;
10072 
10073  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10074  assert(!infeasible);
10075  assert(fixed);
10076 
10077  (*nfixedvars)++;
10078 
10079  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10080  * constraints
10081  */
10083  }
10084  else
10085  {
10086  SCIP_Bool success;
10087 
10088  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10089  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10090  * infeasible we can apply the dual reduction; otherwise we do nothing
10091  */
10092  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10093  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10094  nfixedvars, &success, cutoff) );
10095 
10096  if( success )
10097  {
10099  }
10100  }
10101  }
10102  }
10103  }
10104 
10105  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10106  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10107  }
10108 
10109  /* free temporary memory */
10110  SCIPfreeBufferArray(scip, &uppropubs);
10111  SCIPfreeBufferArray(scip, &upproplbs);
10112  SCIPfreeBufferArray(scip, &upimplubs);
10113  SCIPfreeBufferArray(scip, &upimpllbs);
10114  SCIPfreeBufferArray(scip, &downpropubs);
10115  SCIPfreeBufferArray(scip, &downproplbs);
10116  SCIPfreeBufferArray(scip, &downimplubs);
10117  SCIPfreeBufferArray(scip, &downimpllbs);
10118 
10119  return SCIP_OKAY;
10120 }
10121 
10122 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10123  *
10124  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10125  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10126  *
10127  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10128  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10129  * up-lock of the corresponding start time variable can be removed.
10130  *
10131  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10132  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10133  * positive, than the job can be dual fixed to its latest start time (lst).
10134  *
10135  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10136  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10137  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10138  * of the corresponding job).
10139 
10140  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10141  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10142  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10143  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10144  *
10145  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10146  * the cumulative condition; The deletion has to be done later.
10147  */
10148 static
10150  SCIP* scip, /**< SCIP data structure */
10151  int nvars, /**< number of start time variables (activities) */
10152  SCIP_VAR** vars, /**< array of start time variables */
10153  int* durations, /**< array of durations */
10154  int hmin, /**< left bound of time axis to be considered (including hmin) */
10155  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10156  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10157  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10158  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10159  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10160  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10161  int* nchgsides, /**< pointer to store the number of changed sides */
10162  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10163  )
10164 {
10165  SCIP_Real* downimpllbs;
10166  SCIP_Real* downimplubs;
10167  SCIP_Real* downproplbs;
10168  SCIP_Real* downpropubs;
10169  SCIP_Real* upimpllbs;
10170  SCIP_Real* upimplubs;
10171  SCIP_Real* upproplbs;
10172  SCIP_Real* uppropubs;
10173 
10174  int firstmaxlst;
10175  int secondmaxlst;
10176  int v;
10177 
10178  /* get temporary memory for storing probing results needed for step (4) and (5) */
10179  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10180  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10181  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10182  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10183  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10184  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10185  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10186  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10187 
10188  assert(scip != NULL);
10189  assert(nvars > 1);
10190  assert(cons != NULL);
10191 
10192  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10193 
10194  firstmaxlst = INT_MIN;
10195  secondmaxlst = INT_MIN;
10196 
10197  /* compute the two largest latest start times; which are needed for step (5) */
10198  for( v = 0; v < nvars; ++v )
10199  {
10200  int lst;
10201 
10202  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10203 
10204  if( lst > firstmaxlst )
10205  {
10206  secondmaxlst = firstmaxlst;
10207  firstmaxlst = lst;
10208  }
10209  else if( lst > secondmaxlst )
10210  secondmaxlst = lst;
10211  }
10212 
10213  /* loop over all jobs and check if one of the 5 reductions can be applied */
10214  for( v = 0; v < nvars; ++v )
10215  {
10216  SCIP_VAR* var;
10217  int duration;
10218 
10219  int alternativeub;
10220  int maxlst;
10221  int est;
10222  int ect;
10223  int lst;
10224 
10225  var = vars[v];
10226  assert(var != NULL);
10227 
10228  duration = durations[v];
10229  assert(duration > 0);
10230 
10231  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10232  * time (lct)
10233  */
10234  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10235  ect = est + duration;
10236  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10237 
10238  /* compute the latest start time of all remaining jobs */
10239  if( lst == firstmaxlst )
10240  maxlst = secondmaxlst;
10241  else
10242  maxlst = firstmaxlst;
10243 
10244  /* compute potential alternative upper bound (step (4) and (5)) */
10245  alternativeub = MIN(hmax - 1, maxlst) - duration;
10246  alternativeub = MAX(alternativeub, hmin);
10247 
10248  if( est >= hmax )
10249  {
10250  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10251  * cumulative condition
10252  */
10253  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10254  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10255 
10256  /* mark variable to be irrelevant */
10257  irrelevants[v] = TRUE;
10258 
10259  /* for the statistic we count the number of jobs which are irrelevant */
10260  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10261  }
10262  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10263  {
10264  assert(downlocks != NULL);
10265  assert(uplocks != NULL);
10266 
10267  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10268  * so the up lock can be omitted
10269  */
10270 
10271  if( !downlocks[v] )
10272  {
10273  /* the variables has no down lock and we can also remove the up lock;
10274  * => lst <= hmin and ect >= hmax
10275  * => remove job and reduce capacity by the demand of that job
10276  */
10277  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10278  SCIPvarGetName(var), est, lst, duration);
10279 
10280  /* mark variable to be irrelevant */
10281  irrelevants[v] = TRUE;
10282 
10283  /* for the statistic we count the number of jobs which always run during the effective horizon */
10285  }
10286 
10287  if( uplocks[v] )
10288  {
10289  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10290  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10291 
10292  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10293  uplocks[v] = FALSE;
10294  (*nchgsides)++;
10295 
10296  /* for the statistic we count the number of removed locks */
10298  }
10299  }
10300  else if( lst >= hmax )
10301  {
10302  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10303  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10304  * removed form the cumulative condition after it was fixed to its latest start time
10305  */
10306 
10307  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10308  * bound
10309  */
10310  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10311  {
10312  /* fix integer start time variable if possible to its upper bound */
10313  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10314  }
10315 
10316  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10317  {
10318  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10319  SCIPvarGetName(var), est, lst, duration);
10320 
10321  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10322  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10323 
10324  /* mark variable to be irrelevant */
10325  irrelevants[v] = TRUE;
10326 
10327  /* for the statistic we count the number of jobs which are dual fixed */
10329  }
10330  }
10331  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10332  {
10333  assert(uplocks != NULL);
10334 
10335  /* check step (4) and (5) */
10336 
10337  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10338  * is in favor of rounding the variable down
10339  */
10340  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10341  {
10342  SCIP_Bool roundable;
10343 
10344  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10345 
10346  if( roundable )
10347  {
10348  if( alternativeub < est )
10349  {
10350  SCIP_Bool infeasible;
10351  SCIP_Bool fixed;
10352 
10353  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10354  assert(!infeasible);
10355  assert(fixed);
10356 
10357  (*nfixedvars)++;
10358 
10359  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10360  * constraints
10361  */
10363  }
10364  else
10365  {
10366  SCIP_Bool success;
10367 
10368  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10369  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10370  * in infeasible we can apply the dual reduction; otherwise we do nothing
10371  */
10372  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10373  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10374  nfixedvars, &success, cutoff) );
10375 
10376  if( success )
10377  {
10379  }
10380  }
10381  }
10382  }
10383  }
10384  }
10385 
10386  /* free temporary memory */
10387  SCIPfreeBufferArray(scip, &uppropubs);
10388  SCIPfreeBufferArray(scip, &upproplbs);
10389  SCIPfreeBufferArray(scip, &upimplubs);
10390  SCIPfreeBufferArray(scip, &upimpllbs);
10391  SCIPfreeBufferArray(scip, &downpropubs);
10392  SCIPfreeBufferArray(scip, &downproplbs);
10393  SCIPfreeBufferArray(scip, &downimplubs);
10394  SCIPfreeBufferArray(scip, &downimpllbs);
10395 
10396  return SCIP_OKAY;
10397 }
10398 
10399 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10400 static
10402  SCIP* scip, /**< SCIP data structure */
10403  SCIP_CONS* cons, /**< cumulative constraint */
10404  int* nfixedvars, /**< pointer to store the number of fixed variables */
10405  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10406  int* nchgsides, /**< pointer to store the number of changed sides */
10407  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10408  )
10409 {
10410  SCIP_CONSDATA* consdata;
10411  SCIP_Bool* irrelevants;
10412  int nvars;
10413  int v;
10414 
10415  assert(scip != NULL);
10416  assert(cons != NULL);
10417  assert(!(*cutoff));
10418 
10419  consdata = SCIPconsGetData(cons);
10420  assert(consdata != NULL);
10421 
10422  nvars = consdata->nvars;
10423 
10424  if( nvars <= 1 )
10425  return SCIP_OKAY;
10426 
10427  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10428  BMSclearMemoryArray(irrelevants, nvars);
10429 
10430  /* presolve constraint form the earlier start time point of view */
10431  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10432  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10433  irrelevants, nfixedvars, nchgsides, cutoff) );
10434 
10435  /* presolve constraint form the latest completion time point of view */
10436  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10437  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10438  irrelevants, nfixedvars, nchgsides, cutoff) );
10439 
10440  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10441  * order to ensure a correct behaviour
10442  */
10443  for( v = nvars-1; v >= 0; --v )
10444  {
10445  if( irrelevants[v] )
10446  {
10447  SCIP_VAR* var;
10448  int ect;
10449  int lst;
10450 
10451  var = consdata->vars[v];
10452  assert(var != NULL);
10453 
10454  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10455  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10456 
10457  /* check if the jobs runs completely during the effective horizon */
10458  if( lst <= consdata->hmin && ect >= consdata->hmax )
10459  {
10460  if( consdata->capacity < consdata->demands[v] )
10461  {
10462  *cutoff = TRUE;
10463  break;
10464  }
10465 
10466  consdata->capacity -= consdata->demands[v];
10467  consdata->varbounds = FALSE;
10468  }
10469 
10470  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10471  (*nchgcoefs)++;
10472  }
10473  }
10474 
10475  SCIPfreeBufferArray(scip, &irrelevants);
10476 
10477  return SCIP_OKAY;
10478 }
10479 
10480 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10481 static
10483  SCIP* scip, /**< SCIP data structure */
10484  SCIP_CONSDATA* consdata, /**< constraint data */
10485  int* startindices, /**< permutation with rspect to the start times */
10486  int curtime, /**< current point in time */
10487  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10488  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10489  SCIP_Longint** demands, /**< pointer to array storing the demands */
10490  int* ndemands /**< pointer to store the number of different demands */
10491  )
10492 {
10493  int startindex;
10494  int ncountedvars;
10495 
10496  assert(demands != NULL);
10497  assert(ndemands != NULL);
10498 
10499  ncountedvars = 0;
10500  startindex = nstarted - 1;
10501 
10502  *ndemands = 0;
10503 
10504  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10505  while( nstarted - nfinished > ncountedvars )
10506  {
10507  SCIP_VAR* var;
10508  int endtime;
10509  int varidx;
10510 
10511  /* collect job information */
10512  varidx = startindices[startindex];
10513  assert(varidx >= 0 && varidx < consdata->nvars);
10514 
10515  var = consdata->vars[varidx];
10516  assert(var != NULL);
10517 
10518  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10519 
10520  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10521  if( endtime > curtime )
10522  {
10523  if( consdata->demands[varidx] < consdata->capacity )
10524  {
10525  (*demands)[*ndemands] = consdata->demands[varidx];
10526  (*ndemands)++;
10527  }
10528  ncountedvars++;
10529  }
10530 
10531  startindex--;
10532  }
10533 
10534  return SCIP_OKAY;
10535 }
10536 
10537 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10538  * constraint
10539  */
10540 static
10542  SCIP* scip, /**< SCIP data structure */
10543  SCIP_CONS* cons, /**< constraint to be checked */
10544  int* startindices, /**< permutation with rspect to the start times */
10545  int curtime, /**< current point in time */
10546  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10547  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10548  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10549  )
10550 {
10551  SCIP_CONSDATA* consdata;
10552  SCIP_Longint* demands;
10553  SCIP_Real* profits;
10554  int* items;
10555  int ndemands;
10556  SCIP_Bool success;
10557  SCIP_Real solval;
10558  int j;
10559  assert(nstarted > nfinished);
10560 
10561  consdata = SCIPconsGetData(cons);
10562  assert(consdata != NULL);
10563  assert(consdata->nvars > 0);
10564  assert(consdata->capacity > 0);
10565 
10566  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10567  ndemands = 0;
10568 
10569  /* get demand array to initialize knapsack problem */
10570  SCIP_CALL( collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands) );
10571 
10572  /* create array for profits */
10573  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10574  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10575  for( j = 0; j < ndemands; ++j )
10576  {
10577  profits[j] = (SCIP_Real) demands[j];
10578  items[j] = j;/* this is only a dummy value*/
10579  }
10580 
10581  /* solve knapsack problem and get maximum capacity usage <= capacity */
10582  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10583  items, NULL, NULL, NULL, NULL, &solval, &success) );
10584 
10585  assert(SCIPisFeasIntegral(scip, solval));
10586 
10587  /* store result */
10588  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10589 
10590  SCIPfreeBufferArray(scip, &items);
10591  SCIPfreeBufferArray(scip, &profits);
10592  SCIPfreeBufferArray(scip, &demands);
10593 
10594  return SCIP_OKAY;
10595 }
10596 
10597 /** try to tighten the capacity
10598  * -- using DP for knapsack, we find the maximum possible capacity usage
10599  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10600  */
10601 static
10603  SCIP* scip, /**< SCIP data structure */
10604  SCIP_CONS* cons, /**< cumulative constraint */
10605  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10606  int* nchgsides /**< pointer to store the number of changed sides */
10607  )
10608 {
10609  SCIP_CONSDATA* consdata;
10610  int* starttimes; /* stores when each job is starting */
10611  int* endtimes; /* stores when each job ends */
10612  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10613  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10614 
10615  int nvars; /* number of activities for this constraint */
10616  int freecapacity; /* remaining capacity */
10617  int curtime; /* point in time which we are just checking */
10618  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10619 
10620  int bestcapacity;
10621 
10622  int j;
10623 
10624  assert(scip != NULL);
10625  assert(cons != NULL);
10626  assert(nchgsides != NULL);
10627 
10628  consdata = SCIPconsGetData(cons);
10629  assert(consdata != NULL);
10630 
10631  nvars = consdata->nvars;
10632 
10633  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10634  if( nvars <= 1 || consdata->capacity <= 1 )
10635  return SCIP_OKAY;
10636 
10637  assert(consdata->vars != NULL);
10638 
10639  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10640  SCIPconsGetName(cons), consdata->capacity);
10641 
10642  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10643  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10644  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10645  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10646 
10647  /* create event point arrays */
10648  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10649  starttimes, endtimes, startindices, endindices, FALSE);
10650 
10651  bestcapacity = 1;
10652  endindex = 0;
10653  freecapacity = consdata->capacity;
10654 
10655  /* check each startpoint of a job whether the capacity is kept or not */
10656  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10657  {
10658  curtime = starttimes[j];
10659  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10660 
10661  /* remove the capacity requirments for all job which start at the curtime */
10662  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10663 
10664  /* add the capacity requirments for all job which end at the curtime */
10665  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10666 
10667  assert(freecapacity <= consdata->capacity);
10668  assert(endindex <= nvars);
10669 
10670  /* endindex - points to the next job which will finish */
10671  /* j - points to the last job that has been released */
10672 
10673  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10674  if( freecapacity < 0 )
10675  {
10676  int newcapacity;
10677 
10678  newcapacity = 1;
10679 
10680  /* get best possible upper bound on capacity usage */
10681  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10682 
10683  /* update bestcapacity */
10684  bestcapacity = MAX(bestcapacity, newcapacity);
10685  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10686  }
10687 
10688  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10689  if( freecapacity > 0 && freecapacity != consdata->capacity )
10690  {
10691  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10692  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10693  }
10694 
10695  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10696  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10697  {
10698  /* if demands[startindices[j]] == cap then exactly that job is running */
10699  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10700  bestcapacity = consdata->capacity;
10701  break;
10702  }
10703  } /*lint --e{850}*/
10704 
10705  /* free all buffer arrays */
10706  SCIPfreeBufferArray(scip, &endindices);
10707  SCIPfreeBufferArray(scip, &startindices);
10708  SCIPfreeBufferArray(scip, &endtimes);
10709  SCIPfreeBufferArray(scip, &starttimes);
10710 
10711  /* check whether capacity can be tightened and whether demands need to be adjusted */
10712  if( bestcapacity < consdata->capacity )
10713  {
10714  /* cppcheck-suppress unassignedVariable */
10715  int oldnchgcoefs;
10716 
10717  SCIPdebug(oldnchgcoefs = *nchgcoefs; )
10718 
10719  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10720  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10721 
10722  for( j = 0; j < nvars; ++j )
10723  {
10724  if( consdata->demands[j] == consdata->capacity )
10725  {
10726  consdata->demands[j] = bestcapacity;
10727  (*nchgcoefs)++;
10728  }
10729  }
10730 
10731  consdata->capacity = bestcapacity;
10732  (*nchgsides)++;
10733 
10734  SCIPdebugMsgPrint(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs);
10735 
10736  consdata->varbounds = FALSE;
10737  }
10738 
10739  return SCIP_OKAY;
10740 }
10741 
10742 /** tries to change coefficients:
10743  * demand_j < cap && all other parallel jobs in conflict
10744  * ==> set demand_j := cap
10745  */
10746 static
10748  SCIP* scip, /**< SCIP data structure */
10749  SCIP_CONS* cons, /**< cumulative constraint */
10750  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10751  )
10752 {
10753  SCIP_CONSDATA* consdata;
10754  int nvars;
10755  int j;
10756  int oldnchgcoefs;
10757  int mindemand;
10758 
10759  assert(scip != NULL);
10760  assert(cons != NULL);
10761  assert(nchgcoefs != NULL);
10762 
10763  /* get constraint data for some parameter testings only! */
10764  consdata = SCIPconsGetData(cons);
10765  assert(consdata != NULL);
10766 
10767  nvars = consdata->nvars;
10768  oldnchgcoefs = *nchgcoefs;
10769 
10770  if( nvars <= 0 )
10771  return SCIP_OKAY;
10772 
10773  /* PRE1:
10774  * check all jobs j whether: r_j + r_min > capacity holds
10775  * if so: adjust r_j to capacity
10776  */
10777  mindemand = consdata->demands[0];
10778  for( j = 0; j < nvars; ++j )
10779  {
10780  mindemand = MIN(mindemand, consdata->demands[j]);
10781  }
10782 
10783  /*check each job */
10784  for( j = 0; j < nvars; ++j )
10785  {
10786  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10787  {
10788  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10789  consdata->demands[j], consdata->capacity);
10790  consdata->demands[j] = consdata->capacity;
10791  (*nchgcoefs)++;
10792  }
10793  }
10794 
10795  /* PRE2:
10796  * check for each job (with d_j < cap)
10797  * whether it is disjunctive to all others over the time horizon
10798  */
10799  for( j = 0; j < nvars; ++j )
10800  {
10801  SCIP_Bool chgcoef;
10802  int est_j;
10803  int lct_j;
10804  int i;
10805 
10806  assert(consdata->demands[j] <= consdata->capacity);
10807 
10808  if( consdata->demands[j] == consdata->capacity )
10809  continue;
10810 
10811  chgcoef = TRUE;
10812 
10813  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10814  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10815 
10816  for( i = 0; i < nvars; ++i )
10817  {
10818  int est_i;
10819  int lct_i;
10820 
10821  if( i == j )
10822  continue;
10823 
10824  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10825  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10826 
10827  if( est_i >= lct_j || est_j >= lct_i )
10828  continue;
10829 
10830  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10831  {
10832  chgcoef = FALSE;
10833  break;
10834  }
10835  }
10836 
10837  if( chgcoef )
10838  {
10839  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10840  consdata->demands[j], consdata->capacity);
10841  consdata->demands[j] = consdata->capacity;
10842  (*nchgcoefs)++;
10843  }
10844  }
10845 
10846  if( (*nchgcoefs) > oldnchgcoefs )
10847  {
10848  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10849  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10850  }
10851 
10852  return SCIP_OKAY;
10853 }
10854 
10855 #if 0
10856 /** try to reformulate constraint by replacing certain jobs */
10857 static
10858 SCIP_RETCODE reformulateCons(
10859  SCIP* scip, /**< SCIP data structure */
10860  SCIP_CONS* cons, /**< cumulative constraint */
10861  int* naggrvars /**< pointer to store the number of aggregated variables */
10862  )
10863 {
10864  SCIP_CONSDATA* consdata;
10865  int hmin;
10866  int hmax;
10867  int nvars;
10868  int v;
10869 
10870  consdata = SCIPconsGetData(cons);
10871  assert(cons != NULL);
10872 
10873  nvars = consdata->nvars;
10874  assert(nvars > 1);
10875 
10876  hmin = consdata->hmin;
10877  hmax = consdata->hmax;
10878  assert(hmin < hmax);
10879 
10880  for( v = 0; v < nvars; ++v )
10881  {
10882  SCIP_VAR* var;
10883  int duration;
10884  int est;
10885  int ect;
10886  int lst;
10887  int lct;
10888 
10889  var = consdata->vars[v];
10890  assert(var != NULL);
10891 
10892  duration = consdata->durations[v];
10893 
10894  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10895  ect = est + duration;
10896  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10897  lct = lst + duration;
10898 
10899  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10900  assert(lst > hmin || ect < hmax);
10901 
10902  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10903  {
10904  SCIP_VAR* aggrvar;
10905  char name[SCIP_MAXSTRLEN];
10906  SCIP_Bool infeasible;
10907  SCIP_Bool redundant;
10908  SCIP_Bool aggregated;
10909  int shift;
10910 
10911  shift = est - (hmin - lct + MIN(hmin, ect));
10912  assert(shift > 0);
10913  lst = hmin;
10914  duration = hmin - lct;
10915 
10916  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10917  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10918 
10919  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10920  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10922  SCIP_CALL( SCIPaddVar(scip, var) );
10923  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10924 
10925  assert(!infeasible);
10926  assert(!redundant);
10927  assert(aggregated);
10928 
10929  /* replace variable */
10930  consdata->durations[v] = duration;
10931  consdata->vars[v] = aggrvar;
10932 
10933  /* remove and add locks */
10934  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10935  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10936 
10937  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10938 
10939  (*naggrvars)++;
10940  }
10941  }
10942 
10943  return SCIP_OKAY;
10944 }
10945 #endif
10946 
10947 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10948 static
10950  SCIP* scip, /**< SCIP data structure */
10951  SCIP_CONS* cons, /**< cumulative constraint */
10952  int* naddconss /**< pointer to store the number of added constraints */
10953  )
10954 {
10955  SCIP_CONSDATA* consdata;
10956  SCIP_VAR** vars;
10957  int* durations;
10958  int* demands;
10959  int capacity;
10960  int halfcapacity;
10961  int mindemand;
10962  int nvars;
10963  int v;
10964 
10965  consdata = SCIPconsGetData(cons);
10966  assert(consdata != NULL);
10967 
10968  capacity = consdata->capacity;
10969 
10970  if( capacity == 1 )
10971  return SCIP_OKAY;
10972 
10973  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10974  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10975  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10976 
10977  halfcapacity = capacity / 2;
10978  mindemand = consdata->capacity;
10979  nvars = 0;
10980 
10981  /* collect all jobs with demand larger than half of the capacity */
10982  for( v = 0; v < consdata->nvars; ++v )
10983  {
10984  if( consdata->demands[v] > halfcapacity )
10985  {
10986  vars[nvars] = consdata->vars[v];
10987  demands[nvars] = 1;
10988  durations[nvars] = consdata->durations[v];
10989  nvars++;
10990 
10991  mindemand = MIN(mindemand, consdata->demands[v]);
10992  }
10993  }
10994 
10995  if( nvars > 0 )
10996  {
10997  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10998  * job is still to large to be scheduled in parallel
10999  */
11000  for( v = 0; v < consdata->nvars; ++v )
11001  {
11002  if( consdata->demands[v] > halfcapacity )
11003  continue;
11004 
11005  if( mindemand + consdata->demands[v] > capacity )
11006  {
11007  demands[nvars] = 1;
11008  durations[nvars] = consdata->durations[v];
11009  vars[nvars] = consdata->vars[v];
11010  nvars++;
11011 
11012  /* @todo create one cumulative constraint and look for another small demand */
11013  break;
11014  }
11015  }
11016 
11017  /* creates cumulative constraint and adds it to problem */
11018  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11020  (*naddconss)++;
11021  }
11022 
11023  SCIPfreeBufferArray(scip, &demands);
11024  SCIPfreeBufferArray(scip, &durations);
11025  SCIPfreeBufferArray(scip, &vars);
11026 
11027  return SCIP_OKAY;
11028 }
11029 
11030 /** presolve given constraint */
11031 static
11033  SCIP* scip, /**< SCIP data structure */
11034  SCIP_CONS* cons, /**< cumulative constraint */
11035  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11036  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11037  int* nfixedvars, /**< pointer to store the number of fixed variables */
11038 #if 0
11039  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11040 #endif
11041  int* nchgbds, /**< pointer to store the number of changed bounds */
11042  int* ndelconss, /**< pointer to store the number of deleted constraints */
11043  int* naddconss, /**< pointer to store the number of added constraints */
11044  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11045  int* nchgsides, /**< pointer to store the number of changed sides */
11046  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11047  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11048  )
11049 {
11050  assert(!SCIPconsIsDeleted(cons));
11051 
11052  /* only perform dual reductions on model constraints */
11053  if( conshdlrdata->dualpresolve && SCIPallowDualReds(scip) )
11054  {
11055  /* computes the effective horizon and checks if the constraint can be decomposed */
11056  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11057 
11058  if( SCIPconsIsDeleted(cons) )
11059  return SCIP_OKAY;
11060 
11061  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11062  * fixings (dual reductions)
11063  */
11064  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11065  {
11066  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11067 
11068  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11069  return SCIP_OKAY;
11070  }
11071 
11072  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11073 
11074  if( *cutoff || SCIPconsIsDeleted(cons) )
11075  return SCIP_OKAY;
11076  }
11077 
11078  /* remove jobs which have a demand larger than the capacity */
11079  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11080  assert((*cutoff) || checkDemands(scip, cons));
11081 
11082  if( *cutoff )
11083  return SCIP_OKAY;
11084 
11085  if( conshdlrdata->normalize )
11086  {
11087  /* divide demands by their greatest common divisor */
11088  SCIP_CALL( normalizeDemands(scip, cons, nchgcoefs, nchgsides) );
11089  }
11090 
11091  /* delete constraint with one job */
11092  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11093 
11094  if( *cutoff || SCIPconsIsDeleted(cons) )
11095  return SCIP_OKAY;
11096 
11097  if( conshdlrdata->coeftightening )
11098  {
11099  /* try to tighten the capacity */
11100  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11101 
11102  /* try to tighten the coefficients */
11103  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11104  }
11105 
11106  assert(checkDemands(scip, cons) || *cutoff);
11107 
11108 #if 0
11109  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11110 #endif
11111 
11112  return SCIP_OKAY;
11113 }
11114 
11115 /**@name TClique Graph callbacks
11116  *
11117  * @{
11118  */
11119 
11120 /** tclique graph data */
11121 struct TCLIQUE_Graph
11122 {
11123  SCIP_VAR** vars; /**< start time variables each of them is a node */
11124  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11125  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11126  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11127  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11128  int* ninarcs; /**< number if in arcs for the precedence graph */
11129  int* noutarcs; /**< number if out arcs for the precedence graph */
11130  int* durations; /**< for each node the duration of the corresponding job */
11131  int nnodes; /**< number of nodes */
11132  int size; /**< size of the array */
11133 };
11134 
11135 /** gets number of nodes in the graph */
11136 static
11137 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11139  assert(tcliquegraph != NULL);
11140 
11141  return tcliquegraph->nnodes;
11142 }
11143 
11144 /** gets weight of nodes in the graph */
11145 static
11146 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11148  assert(tcliquegraph != NULL);
11149 
11150  return tcliquegraph->weights;
11151 }
11152 
11153 /** returns, whether the edge (node1, node2) is in the graph */
11154 static
11155 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11157  assert(tcliquegraph != NULL);
11158  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11159  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11160 
11161  /* check if an arc exits in the precedence graph */
11162  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11163  return TRUE;
11164 
11165  /* check if an edge exits in the non-overlapping graph */
11166  if( tcliquegraph->demandmatrix[node1][node2] )
11167  return TRUE;
11168 
11169  return FALSE;
11170 }
11171 
11172 /** selects all nodes from a given set of nodes which are adjacent to a given node
11173  * and returns the number of selected nodes
11174  */
11175 static
11176 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11178  int nadjnodes;
11179  int i;
11180 
11181  assert(tcliquegraph != NULL);
11182  assert(0 <= node && node < tcliquegraph->nnodes);
11183  assert(nnodes == 0 || nodes != NULL);
11184  assert(adjnodes != NULL);
11185 
11186  nadjnodes = 0;
11187 
11188  for( i = 0; i < nnodes; i++ )
11189  {
11190  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11191  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11192  assert(i == 0 || nodes[i-1] < nodes[i]);
11193 
11194  /* check if an edge exists */
11195  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11196  {
11197  /* current node is adjacent to given node */
11198  adjnodes[nadjnodes] = nodes[i];
11199  nadjnodes++;
11200  }
11201  }
11202 
11203  return nadjnodes;
11204 }
11205 
11206 /** generates cuts using a clique found by algorithm for maximum weight clique
11207  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11208  */
11209 static
11210 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11211 { /*lint --e{715}*/
11212  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11213 }
11214 
11215 /** print the tclique graph */
11216 #if 0
11217 static
11218 void tcliquePrint(
11219  SCIP* scip, /**< SCIP data structure */
11220  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11221  )
11222 {
11223  int nnodes;
11224  int i;
11225  int j;
11226 
11227  nnodes = tcliquegraph->nnodes;
11228 
11229  for( i = 0; i < nnodes; ++i )
11230  {
11231  for( j = 0; j < nnodes; ++j )
11232  {
11233  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11234  }
11235  SCIPinfoMessage(scip, NULL, "\n");
11236  }
11237 }
11238 #endif
11239 
11240 /** @} */
11241 
11242 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11243  * job corresponding to variable bound variable (vlbvar)
11244  *
11245  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11246  */
11247 static
11249  SCIP* scip, /**< SCIP data structure */
11250  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11251  SCIP_Real vlbcoef, /**< variable bound coefficient */
11252  SCIP_Real vlbconst, /**< variable bound constant */
11253  int duration /**< duration of the variable bound variable */
11254  )
11255 {
11256  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11257  {
11258  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11259  {
11260  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11261  return TRUE;
11262  }
11263  }
11264  else
11265  {
11266  SCIP_Real bound;
11267 
11268  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11269 
11270  if( SCIPisLT(scip, vlbcoef, 1.0) )
11271  {
11272  SCIP_Real ub;
11273 
11274  ub = SCIPvarGetUbLocal(vlbvar);
11275 
11276  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11277  if( SCIPisLE(scip, ub, bound) )
11278  return TRUE;
11279  }
11280  else
11281  {
11282  SCIP_Real lb;
11283 
11284  assert(SCIPisGT(scip, vlbcoef, 1.0));
11285 
11286  lb = SCIPvarGetLbLocal(vlbvar);
11287 
11288  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11289  if( SCIPisGE(scip, lb, bound) )
11290  return TRUE;
11291  }
11292  }
11293 
11294  return FALSE;
11295 }
11296 
11297 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11298  * job corresponding to variable which is bounded (var)
11299  *
11300  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11301  */
11302 static
11304  SCIP* scip, /**< SCIP data structure */
11305  SCIP_VAR* var, /**< variable which is bound from above */
11306  SCIP_Real vubcoef, /**< variable bound coefficient */
11307  SCIP_Real vubconst, /**< variable bound constant */
11308  int duration /**< duration of the variable which is bounded from above */
11309  )
11310 {
11311  SCIP_Real vlbcoef;
11312  SCIP_Real vlbconst;
11313 
11314  /* convert the variable upper bound into an variable lower bound */
11315  vlbcoef = 1.0 / vubcoef;
11316  vlbconst = -vubconst / vubcoef;
11317 
11318  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11319 }
11320 
11321 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11322  * others an index larger than the number if active variables
11323  */
11324 static
11326  SCIP* scip, /**< SCIP data structure */
11327  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11328  SCIP_VAR* var, /**< variable for which we want the index */
11329  int* idx /**< pointer to store the index */
11330  )
11331 {
11332  (*idx) = SCIPvarGetProbindex(var);
11333 
11334  if( (*idx) == -1 )
11335  {
11336  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11337  {
11338  (*idx) = (int)(size_t) SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var);
11339  }
11340  else
11341  {
11342  int pos;
11343  int v;
11344 
11345  /**@todo we might want to add the aggregation path to graph */
11346 
11347  /* check if we have to realloc memory */
11348  if( tcliquegraph->size == tcliquegraph->nnodes )
11349  {
11350  int size;
11351 
11352  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11353  tcliquegraph->size = size;
11354 
11355  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11356  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11357  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11358  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11359  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11360 
11361  for( v = 0; v < tcliquegraph->nnodes; ++v )
11362  {
11363  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11364  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11365  }
11366  }
11367  assert(tcliquegraph->nnodes < tcliquegraph->size);
11368 
11369  pos = tcliquegraph->nnodes;
11370  assert(pos >= 0);
11371 
11372  tcliquegraph->durations[pos] = 0;
11373  tcliquegraph->weights[pos] = 0;
11374  tcliquegraph->vars[pos] = var;
11375 
11376  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11377  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11378 
11379  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11380  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11381 
11382  SCIP_CALL( SCIPhashmapInsert(tcliquegraph->varmap, (void*)var, (void*)(size_t)(pos)) );
11383 
11384  tcliquegraph->nnodes++;
11385 
11386  for( v = 0; v < tcliquegraph->nnodes; ++v )
11387  {
11388  tcliquegraph->precedencematrix[v][pos] = 0;
11389  tcliquegraph->demandmatrix[v][pos] = 0;
11390  }
11391 
11392  (*idx) = tcliquegraph->nnodes;
11393  }
11394  }
11395  else
11396  {
11397  assert(*idx == (int)(size_t)SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var));
11398  }
11399 
11400  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11401 
11402  return SCIP_OKAY;
11403 }
11404 
11405 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11406  *
11407  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11408  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11409  *
11410  * (i) b = 1 and c >= d
11411  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11412  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11413  *
11414  */
11415 static
11417  SCIP* scip, /**< SCIP data structure */
11418  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11419  )
11420 {
11421  SCIP_VAR** vars;
11422  int nvars;
11423  int v;
11424 
11425  vars = SCIPgetVars(scip);
11426  nvars = SCIPgetNVars(scip);
11427 
11428  /* try to project each arc of the variable bound graph to precedence condition */
11429  for( v = 0; v < nvars; ++v )
11430  {
11431  SCIP_VAR** vbdvars;
11432  SCIP_VAR* var;
11433  SCIP_Real* vbdcoefs;
11434  SCIP_Real* vbdconsts;
11435  int nvbdvars;
11436  int idx1;
11437  int b;
11438 
11439  var = vars[v];
11440  assert(var != NULL);
11441 
11442  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11443  assert(idx1 >= 0);
11444 
11445  if( tcliquegraph->durations[idx1] == 0 )
11446  continue;
11447 
11448  vbdvars = SCIPvarGetVlbVars(var);
11449  vbdcoefs = SCIPvarGetVlbCoefs(var);
11450  vbdconsts = SCIPvarGetVlbConstants(var);
11451  nvbdvars = SCIPvarGetNVlbs(var);
11452 
11453  for( b = 0; b < nvbdvars; ++b )
11454  {
11455  int idx2;
11456 
11457  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11458  assert(idx2 >= 0);
11459 
11460  if( tcliquegraph->durations[idx2] == 0 )
11461  continue;
11462 
11463  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11464  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11465  }
11466 
11467  vbdvars = SCIPvarGetVubVars(var);
11468  vbdcoefs = SCIPvarGetVubCoefs(var);
11469  vbdconsts = SCIPvarGetVubConstants(var);
11470  nvbdvars = SCIPvarGetNVubs(var);
11471 
11472  for( b = 0; b < nvbdvars; ++b )
11473  {
11474  int idx2;
11475 
11476  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11477  assert(idx2 >= 0);
11478 
11479  if( tcliquegraph->durations[idx2] == 0 )
11480  continue;
11481 
11482  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11483  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11484  }
11485 
11486  for( b = v+1; b < nvars; ++b )
11487  {
11488  int idx2;
11489 
11490  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11491  assert(idx2 >= 0);
11492 
11493  if( tcliquegraph->durations[idx2] == 0 )
11494  continue;
11495 
11496  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11497  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11498  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11499 
11500  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11501  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11502  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11503  }
11504  }
11505 
11506  return SCIP_OKAY;
11507 }
11508 
11509 /** compute the transitive closer of the given graph and the number of in and out arcs */
11510 static
11511 void transitiveClosure(
11512  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11513  int* ninarcs, /**< array to store the number of in arcs */
11514  int* noutarcs, /**< array to store the number of out arcs */
11515  int nnodes /**< number if nodes */
11516  )
11517 {
11518  int i;
11519  int j;
11520  int k;
11521 
11522  for( i = 0; i < nnodes; ++i )
11523  {
11524  for( j = 0; j < nnodes; ++j )
11525  {
11526  if( adjmatrix[i][j] )
11527  {
11528  ninarcs[j]++;
11529  noutarcs[i]++;
11530 
11531  for( k = 0; k < nnodes; ++k )
11532  {
11533  if( adjmatrix[j][k] )
11534  adjmatrix[i][k] = TRUE;
11535  }
11536  }
11537  }
11538  }
11539 }
11540 
11541 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11542 static
11544  SCIP* scip, /**< SCIP data structure */
11545  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11546  SCIP_CONS** conss, /**< array of cumulative constraints */
11547  int nconss /**< number of cumulative constraints */
11548  )
11549 {
11550  int c;
11551 
11552  /* use the cumulative constraints to initialize the none overlapping graph */
11553  for( c = 0; c < nconss; ++c )
11554  {
11555  SCIP_CONSDATA* consdata;
11556  SCIP_VAR** vars;
11557  int* demands;
11558  int capacity;
11559  int nvars;
11560  int i;
11561 
11562  consdata = SCIPconsGetData(conss[c]);
11563  assert(consdata != NULL);
11564 
11565  vars = consdata->vars;
11566  demands = consdata->demands;
11567 
11568  nvars = consdata->nvars;
11569  capacity = consdata->capacity;
11570 
11571  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11572 
11573  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11574  for( i = 0; i < nvars; ++i )
11575  {
11576  int idx1;
11577  int j;
11578 
11579  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11580  assert(idx1 >= 0);
11581 
11582  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11583  continue;
11584 
11585  for( j = i+1; j < nvars; ++j )
11586  {
11587  assert(consdata->durations[j] > 0);
11588 
11589  if( demands[i] + demands[j] > capacity )
11590  {
11591  int idx2;
11592  int est1;
11593  int est2;
11594  int lct1;
11595  int lct2;
11596 
11597  /* check if the effective horizon is large enough */
11598  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11599  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11600 
11601  /* at least one of the jobs needs to start at hmin or later */
11602  if( est1 < consdata->hmin && est2 < consdata->hmin )
11603  continue;
11604 
11605  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11606  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11607 
11608  /* at least one of the jobs needs to finish not later then hmin */
11609  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11610  continue;
11611 
11612  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11613  assert(idx2 >= 0);
11614  assert(idx1 != idx2);
11615 
11616  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11617  continue;
11618 
11619  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11620 
11621  assert(tcliquegraph->durations[idx1] > 0);
11622  assert(tcliquegraph->durations[idx2] > 0);
11623 
11624  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11625  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11626  }
11627  }
11628  }
11629  }
11630 
11631  return SCIP_OKAY;
11632 }
11633 
11634 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11635  * of jobs cannot run in parallel
11636  */
11637 static
11639  SCIP* scip, /**< SCIP data structure */
11640  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11641  SCIP_CONS** conss, /**< array of cumulative constraints */
11642  int nconss /**< number of cumulative constraints */
11643  )
11644 {
11645  assert(scip != NULL);
11646  assert(tcliquegraph != NULL);
11647 
11648  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11649  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11650 
11651  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11652  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11653 
11654  /* constraints non-overlapping graph */
11655  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11656 
11657  return SCIP_OKAY;
11658 }
11659 
11660 /** create cumulative constraint from conflict set */
11661 static
11663  SCIP* scip, /**< SCIP data structure */
11664  const char* name, /**< constraint name */
11665  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11666  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11667  int ncliquenodes /**< number of nodes in the clique */
11668  )
11669 {
11670  SCIP_CONS* cons;
11671  SCIP_VAR** vars;
11672  int* durations;
11673  int* demands;
11674  int v;
11675 
11676  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11677  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11678  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11679 
11680  SCIPsortInt(cliquenodes, ncliquenodes);
11681 
11682  /* collect variables, durations, and demands */
11683  for( v = 0; v < ncliquenodes; ++v )
11684  {
11685  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11686  assert(durations[v] > 0);
11687  demands[v] = 1;
11688  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11689  }
11690 
11691  /* create (unary) cumulative constraint */
11692  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11694 
11695  SCIP_CALL( SCIPaddCons(scip, cons) );
11696  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11697 
11698  /* free buffers */
11699  SCIPfreeBufferArray(scip, &demands);
11700  SCIPfreeBufferArray(scip, &durations);
11701  SCIPfreeBufferArray(scip, &vars);
11702 
11703  return SCIP_OKAY;
11704 }
11705 
11706 /** search for cumulative constrainst */
11707 static
11709  SCIP* scip, /**< SCIP data structure */
11710  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11711  int* naddconss /**< pointer to store the number of added constraints */
11712  )
11713 {
11714  TCLIQUE_STATUS tcliquestatus;
11715  SCIP_Bool* precedencerow;
11716  SCIP_Bool* precedencecol;
11717  SCIP_Bool* demandrow;
11718  SCIP_Bool* demandcol;
11719  SCIP_HASHTABLE* covered;
11720  int* cliquenodes;
11721  int ncliquenodes;
11722  int cliqueweight;
11723  int ntreenodes;
11724  int nnodes;
11725  int nconss;
11726  int v;
11727 
11728  nnodes = tcliquegraph->nnodes;
11729  nconss = 0;
11730 
11731  /* initialize the weight of each job with its duration */
11732  for( v = 0; v < nnodes; ++v )
11733  {
11734  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11735  }
11736 
11737  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11738  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11739  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11740  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11741  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11742 
11743  /* create a hash table to store all start time variables which are already covered by at least one clique */
11744  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11745  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11746 
11747  /* for each variables/job we are ... */
11748  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11749  {
11750  char name[SCIP_MAXSTRLEN];
11751  int c;
11752 
11753  /* jobs with zero durations are skipped */
11754  if( tcliquegraph->durations[v] == 0 )
11755  continue;
11756 
11757  /* check if the start time variable is already covered by at least one clique */
11758  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11759  continue;
11760 
11761  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11762 
11763  /* temporarily remove the connection via the precedence graph */
11764  for( c = 0; c < nnodes; ++c )
11765  {
11766  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11767  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11768 
11769  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11770  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11771 
11772 #if 0
11773  if( precedencerow[c] || precedencecol[c] )
11774  {
11775  tcliquegraph->demandmatrix[v][c] = FALSE;
11776  tcliquegraph->demandmatrix[c][v] = FALSE;
11777  }
11778 #endif
11779 
11780  tcliquegraph->precedencematrix[c][v] = FALSE;
11781  tcliquegraph->precedencematrix[v][c] = FALSE;
11782  }
11783 
11784  /* find (heuristically) maximum cliques which includes node v */
11785  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11786  tcliquegraph, tcliqueNewsolClique, NULL,
11787  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11788  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11789 
11790  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11791 
11792  if( ncliquenodes == 1 )
11793  continue;
11794 
11795  /* construct constraint name */
11796  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11797 
11798  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11799  nconss++;
11800 
11801  /* all start time variable to covered hash table */
11802  for( c = 0; c < ncliquenodes; ++c )
11803  {
11804  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11805  }
11806 
11807  /* copy the precedence relations back */
11808  for( c = 0; c < nnodes; ++c )
11809  {
11810  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11811  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11812 
11813  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11814  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11815  }
11816  }
11817 
11818  SCIPhashtableFree(&covered);
11819 
11820  SCIPfreeBufferArray(scip, &demandcol);
11821  SCIPfreeBufferArray(scip, &demandrow);
11822  SCIPfreeBufferArray(scip, &precedencecol);
11823  SCIPfreeBufferArray(scip, &precedencerow);
11824  SCIPfreeBufferArray(scip, &cliquenodes);
11825 
11826  (*naddconss) += nconss;
11827 
11828  /* for the statistic we count the number added disjunctive constraints */
11829  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11830 
11831  return SCIP_OKAY;
11832 }
11833 
11834 /** create precedence constraint (as variable bound constraint */
11835 static
11837  SCIP* scip, /**< SCIP data structure */
11838  const char* name, /**< constraint name */
11839  SCIP_VAR* var, /**< variable x that has variable bound */
11840  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11841  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11842  )
11843 {
11844  SCIP_CONS* cons;
11845 
11846  /* create variable bound constraint */
11847  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11849 
11850  SCIPdebugPrintCons(scip, cons, NULL);
11851 
11852  /* add constraint to problem and release it */
11853  SCIP_CALL( SCIPaddCons(scip, cons) );
11854  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11855 
11856  return SCIP_OKAY;
11857 }
11858 
11859 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11860 static
11862  SCIP* scip, /**< SCIP data structure */
11863  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11864  int source, /**< index of the source node */
11865  int sink, /**< index of the sink node */
11866  int* naddconss /**< pointer to store the number of added constraints */
11867  )
11868 {
11869  TCLIQUE_WEIGHT cliqueweight;
11870  TCLIQUE_STATUS tcliquestatus;
11871  SCIP_VAR** vars;
11872  int* cliquenodes;
11873  int nnodes;
11874  int lct;
11875  int est;
11876  int i;
11877 
11878  int ntreenodes;
11879  int ncliquenodes;
11880 
11881  /* check if source and sink are connencted */
11882  if( !tcliquegraph->precedencematrix[source][sink] )
11883  return SCIP_OKAY;
11884 
11885  nnodes = tcliquegraph->nnodes;
11886  vars = tcliquegraph->vars;
11887 
11888  /* reset the weights to zero */
11889  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11890 
11891  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11892  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11893  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11894 
11895  /* weight all jobs which run for sure between source and sink with their duration */
11896  for( i = 0; i < nnodes; ++i )
11897  {
11898  SCIP_VAR* var;
11899  int duration;
11900 
11901  var = vars[i];
11902  assert(var != NULL);
11903 
11904  duration = tcliquegraph->durations[i];
11905 
11906  if( i == source || i == sink )
11907  {
11908  /* source and sink are not weighted */
11909  tcliquegraph->weights[i] = 0;
11910  }
11911  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11912  {
11913  /* job i runs after source and before sink */
11914  tcliquegraph->weights[i] = duration;
11915  }
11916  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11917  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11918  {
11919  /* job i run in between due the bounds of the start time variables */
11920  tcliquegraph->weights[i] = duration;
11921  }
11922  else
11923  tcliquegraph->weights[i] = 0;
11924  }
11925 
11926  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11927 
11928  /* find (heuristically) maximum cliques */
11929  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11930  tcliquegraph, tcliqueNewsolClique, NULL,
11931  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11932  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11933 
11934  if( ncliquenodes > 1 )
11935  {
11936  char name[SCIP_MAXSTRLEN];
11937  int distance;
11938 
11939  /* construct constraint name */
11940  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11941 
11942  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11943  * duration of the source job
11944  */
11945  distance = cliqueweight + tcliquegraph->durations[source];
11946 
11947  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11948  (*naddconss)++;
11949  }
11950 
11951  SCIPfreeBufferArray(scip, &cliquenodes);
11952 
11953  return SCIP_OKAY;
11954 }
11955 
11956 /** search for precedence constraints
11957  *
11958  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11959  * corresponding two jobs
11960  */
11961 static
11963  SCIP* scip, /**< SCIP data structure */
11964  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11965  int* naddconss /**< pointer to store the number of added constraints */
11966  )
11967 {
11968  int* sources;
11969  int* sinks;
11970  int nconss;
11971  int nnodes;
11972  int nsources;
11973  int nsinks;
11974  int i;
11975 
11976  nnodes = tcliquegraph->nnodes;
11977  nconss = 0;
11978 
11979  nsources = 0;
11980  nsinks = 0;
11981 
11982  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
11983  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
11984 
11985  /* first collect all sources and sinks */
11986  for( i = 0; i < nnodes; ++i )
11987  {
11988  if( tcliquegraph->ninarcs[i] == 0 )
11989  {
11990  sources[nsources] = i;
11991  nsources++;
11992  }
11993 
11994  if( tcliquegraph->ninarcs[i] == 0 )
11995  {
11996  sinks[nsinks] = i;
11997  nsinks++;
11998  }
11999  }
12000 
12001  /* compute for each node a minimum distance to each sources and each sink */
12002  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12003  {
12004  int j;
12005 
12006  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12007  {
12008  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12009  }
12010 
12011  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12012  {
12013  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12014  }
12015  }
12016 
12017  (*naddconss) += nconss;
12018 
12019  /* for the statistic we count the number added variable constraints */
12020  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12021 
12022  SCIPfreeBufferArray(scip, &sinks);
12023  SCIPfreeBufferArray(scip, &sources);
12024 
12025  return SCIP_OKAY;
12026 }
12027 
12028 /** initialize the assumed durations for each variable */
12029 static
12031  SCIP* scip, /**< SCIP data structure */
12032  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12033  SCIP_CONS** conss, /**< cumulative constraints */
12034  int nconss /**< number of cumulative constraints */
12035  )
12036 {
12037  int c;
12038 
12039  /* use the cumulative structure to define the duration we are using for each job */
12040  for( c = 0; c < nconss; ++c )
12041  {
12042  SCIP_CONSDATA* consdata;
12043  SCIP_VAR** vars;
12044  int nvars;
12045  int v;
12046 
12047  consdata = SCIPconsGetData(conss[c]);
12048  assert(consdata != NULL);
12049 
12050  vars = consdata->vars;
12051  nvars = consdata->nvars;
12052 
12053  for( v = 0; v < nvars; ++v )
12054  {
12055  int idx;
12056 
12057  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12058  assert(idx >= 0);
12059 
12060  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12061  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12062  * general this is not the case. Therefore, the question would be which duration should be used?
12063  */
12064  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12065  assert(tcliquegraph->durations[idx] > 0);
12066  }
12067  }
12068 
12069  return SCIP_OKAY;
12070 }
12071 
12072 /** create tclique graph */
12073 static
12075  SCIP* scip, /**< SCIP data structure */
12076  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12077  )
12078 {
12079  SCIP_VAR** vars;
12080  SCIP_HASHMAP* varmap;
12081  SCIP_Bool** precedencematrix;
12082  SCIP_Bool** demandmatrix;
12083  int* ninarcs;
12084  int* noutarcs;
12085  int* durations;
12086  int* weights;
12087  int nvars;
12088  int v;
12089 
12090  vars = SCIPgetVars(scip);
12091  nvars = SCIPgetNVars(scip);
12092 
12093  /* allocate memory for the tclique graph data structure */
12094  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12095 
12096  /* create the variable mapping hash map */
12097  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12098 
12099  /* each active variables get a node in the graph */
12100  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12101 
12102  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12103  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12104  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12105 
12106  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12107  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12108  BMSclearMemoryArray(weights, nvars);
12109 
12110  /* array to store the number of in arc of the precedence graph */
12111  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12112  BMSclearMemoryArray(ninarcs, nvars);
12113 
12114  /* array to store the number of out arc of the precedence graph */
12115  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12116  BMSclearMemoryArray(noutarcs, nvars);
12117 
12118  /* array to store the used duration for each node */
12119  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12120  BMSclearMemoryArray(durations, nvars);
12121 
12122  for( v = 0; v < nvars; ++v )
12123  {
12124  SCIP_VAR* var;
12125 
12126  var = vars[v];
12127  assert(var != NULL);
12128 
12129  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12130  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12131 
12132  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12133  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12134 
12135  /* insert all active variables into the garph */
12136  assert(SCIPvarGetProbindex(var) == v);
12137  SCIP_CALL( SCIPhashmapInsert(varmap, (void*)var, (void*)(size_t)v) ); /*lint !e571*/
12138  }
12139 
12140  (*tcliquegraph)->nnodes = nvars;
12141  (*tcliquegraph)->varmap = varmap;
12142  (*tcliquegraph)->precedencematrix = precedencematrix;
12143  (*tcliquegraph)->demandmatrix = demandmatrix;
12144  (*tcliquegraph)->weights = weights;
12145  (*tcliquegraph)->ninarcs = ninarcs;
12146  (*tcliquegraph)->noutarcs = noutarcs;
12147  (*tcliquegraph)->durations = durations;
12148  (*tcliquegraph)->size = nvars;
12149 
12150  return SCIP_OKAY;
12151 }
12152 
12153 /** frees the tclique graph */
12154 static
12155 void freeTcliqueGraph(
12156  SCIP* scip, /**< SCIP data structure */
12157  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12158  )
12159 {
12160  int v;
12161 
12162  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12163  {
12164  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12165  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12166  }
12167 
12168  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12169  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12170  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12171  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12172  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12173  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12174  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12175  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12176 
12177  SCIPfreeBuffer(scip, tcliquegraph);
12178 }
12179 
12180 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12181  * constrains (disjunctive constraint)
12182  */
12183 static
12185  SCIP* scip, /**< SCIP data structure */
12186  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12187  SCIP_CONS** conss, /**< array of cumulative constraints */
12188  int nconss, /**< number of cumulative constraints */
12189  int* naddconss /**< pointer to store the number of added constraints */
12190  )
12191 {
12192  TCLIQUE_GRAPH* tcliquegraph;
12193 
12194  /* create tclique graph */
12195  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12196 
12197  /* define for each job a duration */
12198  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12199 
12200  /* constuct incompatibility graph */
12201  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12202 
12203  /* search for new precedence constraints */
12204  if( conshdlrdata->detectvarbounds )
12205  {
12206  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12207  }
12208 
12209  /* search for new cumulative constraints */
12210  if( conshdlrdata->detectdisjunctive )
12211  {
12212  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12213  }
12214 
12215  /* free tclique graph data structure */
12216  freeTcliqueGraph(scip, &tcliquegraph);
12217 
12218  return SCIP_OKAY;
12219 }
12220 
12221 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12222 static
12224  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12225  )
12226 {
12227  SCIP_VAR** vars;
12228  int nvars;
12229  int v;
12230 
12231  if( consdata->validsignature )
12232  return;
12233 
12234  vars = consdata->vars;
12235  nvars = consdata->nvars;
12236 
12237  for( v = 0; v < nvars; ++v )
12238  {
12239  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12240  }
12241 
12242  consdata->validsignature = TRUE;
12243 }
12244 
12245 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12246 static
12247 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12248 { /*lint --e{715}*/
12249  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12250 
12251  assert(consdata != NULL);
12252  assert(0 <= ind1 && ind1 < consdata->nvars);
12253  assert(0 <= ind2 && ind2 < consdata->nvars);
12254 
12255  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12256 }
12257 
12258 /** run a pairwise comparison */
12259 static
12261  SCIP* scip, /**< SCIP data structure */
12262  SCIP_CONS** conss, /**< array of cumulative constraints */
12263  int nconss, /**< number of cumulative constraints */
12264  int* ndelconss /**< pointer to store the number of deletedconstraints */
12265  )
12266 {
12267  int i;
12268  int j;
12269 
12270  for( i = 0; i < nconss; ++i )
12271  {
12272  SCIP_CONSDATA* consdata0;
12273  SCIP_CONS* cons0;
12274 
12275  cons0 = conss[i];
12276  assert(cons0 != NULL);
12277 
12278  consdata0 = SCIPconsGetData(cons0);
12279  assert(consdata0 != NULL);
12280 
12281  consdataCalcSignature(consdata0);
12282  assert(consdata0->validsignature);
12283 
12284  for( j = i+1; j < nconss; ++j )
12285  {
12286  SCIP_CONSDATA* consdata1;
12287  SCIP_CONS* cons1;
12288 
12289  cons1 = conss[j];
12290  assert(cons1 != NULL);
12291 
12292  consdata1 = SCIPconsGetData(cons1);
12293  assert(consdata1 != NULL);
12294 
12295  if( consdata0->capacity != consdata1->capacity )
12296  continue;
12297 
12298  consdataCalcSignature(consdata1);
12299  assert(consdata1->validsignature);
12300 
12301  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12302  {
12303  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12304  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12305  assert((consdata0->signature & (~consdata1->signature)) == 0);
12306  }
12307 
12308  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12309  {
12310  int* perm0;
12311  int* perm1;
12312  int v0;
12313  int v1;
12314 
12315  if( consdata0->nvars > consdata1->nvars )
12316  continue;
12317 
12318  if( consdata0->hmin < consdata1->hmin )
12319  continue;
12320 
12321  if( consdata0->hmax > consdata1->hmax )
12322  continue;
12323 
12324  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12325  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12326 
12327  /* call sorting method */
12328  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12329  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12330 
12331  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12332  {
12333  SCIP_VAR* var0;
12334  SCIP_VAR* var1;
12335  int idx0;
12336  int idx1;
12337  int comp;
12338 
12339  idx0 = perm0[v0];
12340  idx1 = perm1[v1];
12341 
12342  var0 = consdata0->vars[idx0];
12343 
12344  var1 = consdata1->vars[idx1];
12345 
12346  comp = SCIPvarCompare(var0, var1);
12347 
12348  if( comp == 0 )
12349  {
12350  int duration0;
12351  int duration1;
12352  int demand0;
12353  int demand1;
12354 
12355  demand0 = consdata0->demands[idx0];
12356  duration0 = consdata0->durations[idx0];
12357 
12358  demand1 = consdata1->demands[idx1];
12359  duration1 = consdata1->durations[idx1];
12360 
12361  if( demand0 != demand1 )
12362  break;
12363 
12364  if( duration0 != duration1 )
12365  break;
12366 
12367  v0++;
12368  v1++;
12369  }
12370  else if( comp > 0 )
12371  v1++;
12372  else
12373  break;
12374  }
12375 
12376  if( v0 == consdata0->nvars )
12377  {
12378  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12379  {
12380  initializeLocks(consdata1, TRUE);
12381  }
12382 
12383  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12384 
12385  SCIP_CALL( SCIPdelCons(scip, cons0) );
12386  (*ndelconss)++;
12387  }
12388 
12389  SCIPfreeBufferArray(scip, &perm1);
12390  SCIPfreeBufferArray(scip, &perm0);
12391  }
12392  }
12393  }
12394 
12395  return SCIP_OKAY;
12396 }
12397 
12398 /** strengthen the variable bounds using the cumulative condition */
12399 static
12401  SCIP* scip, /**< SCIP data structure */
12402  SCIP_CONS* cons, /**< constraint to propagate */
12403  int* nchgbds, /**< pointer to store the number of changed bounds */
12404  int* naddconss /**< pointer to store the number of added constraints */
12405  )
12406 {
12407  SCIP_CONSDATA* consdata;
12408  SCIP_VAR** vars;
12409  int* durations;
12410  int* demands;
12411  int capacity;
12412  int nvars;
12413  int nconss;
12414  int i;
12415 
12416  consdata = SCIPconsGetData(cons);
12417  assert(consdata != NULL);
12418 
12419  /* check if the variable bounds got already strengthen by the cumulative constraint */
12420  if( consdata->varbounds )
12421  return SCIP_OKAY;
12422 
12423  vars = consdata->vars;
12424  durations = consdata->durations;
12425  demands = consdata->demands;
12426  capacity = consdata->capacity;
12427  nvars = consdata->nvars;
12428 
12429  nconss = 0;
12430 
12431  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12432  {
12433  SCIP_VAR** vbdvars;
12434  SCIP_VAR* var;
12435  SCIP_Real* vbdcoefs;
12436  SCIP_Real* vbdconsts;
12437  int nvbdvars;
12438  int b;
12439  int j;
12440 
12441  var = consdata->vars[i];
12442  assert(var != NULL);
12443 
12444  vbdvars = SCIPvarGetVlbVars(var);
12445  vbdcoefs = SCIPvarGetVlbCoefs(var);
12446  vbdconsts = SCIPvarGetVlbConstants(var);
12447  nvbdvars = SCIPvarGetNVlbs(var);
12448 
12449  for( b = 0; b < nvbdvars; ++b )
12450  {
12451  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12452  {
12453  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12454  {
12455  for( j = 0; j < nvars; ++j )
12456  {
12457  if( vars[j] == vbdvars[b] )
12458  break;
12459  }
12460  if( j == nvars )
12461  continue;
12462 
12463  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12464  {
12465  SCIP_Bool infeasible;
12466  char name[SCIP_MAXSTRLEN];
12467  int nlocalbdchgs;
12468 
12469  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12470 
12471  /* construct constraint name */
12472  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12473 
12474  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12475  nconss++;
12476 
12477  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12478  assert(!infeasible);
12479 
12480  (*nchgbds) += nlocalbdchgs;
12481  }
12482  }
12483  }
12484  }
12485  }
12486 
12487  (*naddconss) += nconss;
12488 
12489  consdata->varbounds = TRUE;
12490 
12491  return SCIP_OKAY;
12492 }
12493 
12494 /** helper function to enforce constraints */
12495 static
12497  SCIP* scip, /**< SCIP data structure */
12498  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12499  SCIP_CONS** conss, /**< constraints to process */
12500  int nconss, /**< number of constraints */
12501  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12502  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12503  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12504  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12505  )
12506 {
12507  SCIP_CONSHDLRDATA* conshdlrdata;
12508 
12509  assert(conshdlr != NULL);
12510  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12511  assert(nconss == 0 || conss != NULL);
12512  assert(result != NULL);
12513 
12514  if( solinfeasible )
12515  {
12516  *result = SCIP_INFEASIBLE;
12517  return SCIP_OKAY;
12518  }
12519 
12520  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12521  sol == NULL ? "LP" : "relaxation");
12522 
12523  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12524  assert(conshdlrdata != NULL);
12525 
12526  (*result) = SCIP_FEASIBLE;
12527 
12528  if( conshdlrdata->usebinvars )
12529  {
12530  SCIP_Bool separated;
12531  SCIP_Bool cutoff;
12532  int c;
12533 
12534  separated = FALSE;
12535 
12536  /* first check if a constraints is violated */
12537  for( c = 0; c < nusefulconss; ++c )
12538  {
12539  SCIP_CONS* cons;
12540  SCIP_Bool violated;
12541 
12542  cons = conss[c];
12543  assert(cons != NULL);
12544 
12545  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12546 
12547  if( !violated )
12548  continue;
12549 
12550  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12551  if ( cutoff )
12552  {
12553  *result = SCIP_CUTOFF;
12554  return SCIP_OKAY;
12555  }
12556  }
12557 
12558  for( ; c < nconss && !separated; ++c )
12559  {
12560  SCIP_CONS* cons;
12561  SCIP_Bool violated;
12562 
12563  cons = conss[c];
12564  assert(cons != NULL);
12565 
12566  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12567 
12568  if( !violated )
12569  continue;
12570 
12571  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12572  if ( cutoff )
12573  {
12574  *result = SCIP_CUTOFF;
12575  return SCIP_OKAY;
12576  }
12577  }
12578 
12579  if( separated )
12580  (*result) = SCIP_SEPARATED;
12581  }
12582  else
12583  {
12584  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12585  }
12586 
12587  return SCIP_OKAY;
12588 }
12589 
12590 /**@} */
12591 
12592 
12593 /**@name Callback methods of constraint handler
12594  *
12595  * @{
12596  */
12597 
12598 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12599 static
12600 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12601 { /*lint --e{715}*/
12602  assert(scip != NULL);
12603  assert(conshdlr != NULL);
12604  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12605 
12606  /* call inclusion method of constraint handler */
12608 
12610 
12611  *valid = TRUE;
12612 
12613  return SCIP_OKAY;
12614 }
12615 
12616 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12617 static
12618 SCIP_DECL_CONSFREE(consFreeCumulative)
12619 { /*lint --e{715}*/
12620  SCIP_CONSHDLRDATA* conshdlrdata;
12621 
12622  assert(conshdlr != NULL);
12623  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12624 
12625  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12626  assert(conshdlrdata != NULL);
12627 
12628 #ifdef SCIP_STATISTIC
12629  if( !conshdlrdata->iscopy )
12630  {
12631  /* statisitc output if SCIP_STATISTIC is defined */
12632  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12633  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12634  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12635  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12636  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12637  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12638  }
12639 #endif
12640 
12641  conshdlrdataFree(scip, &conshdlrdata);
12642 
12643  SCIPconshdlrSetData(conshdlr, NULL);
12644 
12645  return SCIP_OKAY;
12646 }
12647 
12648 
12649 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12650 static
12651 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12652 { /*lint --e{715}*/
12653  SCIP_CONSHDLRDATA* conshdlrdata;
12654  int c;
12655 
12656  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12657  assert(conshdlrdata != NULL);
12658 
12659  conshdlrdata->detectedredundant = FALSE;
12660 
12661  for( c = 0; c < nconss; ++c )
12662  {
12663  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12664  * hmax)
12665  */
12666  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12667  }
12668 
12669  return SCIP_OKAY;
12670 }
12671 
12672 
12673 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12674 #ifdef SCIP_STATISTIC
12675 static
12676 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12677 { /*lint --e{715}*/
12678  SCIP_CONSHDLRDATA* conshdlrdata;
12679  int c;
12680 
12681  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12682  assert(conshdlrdata != NULL);
12683 
12684  for( c = 0; c < nconss; ++c )
12685  {
12686  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12687 
12688 #if 0
12689  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12690 #endif
12691  }
12692 
12693  if( !conshdlrdata->iscopy )
12694  {
12695  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12696  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12697  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12698  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12699  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12700  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12701  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12702  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12703  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12704  }
12705 
12706  return SCIP_OKAY;
12707 }
12708 #endif
12709 
12710 
12711 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12712 static
12713 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12714 { /*lint --e{715}*/
12715  SCIP_CONSDATA* consdata;
12716  int c;
12717 
12718  assert(conshdlr != NULL);
12719  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12720 
12721  /* release the rows of all constraints */
12722  for( c = 0; c < nconss; ++c )
12723  {
12724  consdata = SCIPconsGetData(conss[c]);
12725  assert(consdata != NULL);
12726 
12727  /* free rows */
12728  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12729  }
12730 
12731  return SCIP_OKAY;
12732 }
12733 
12734 /** frees specific constraint data */
12735 static
12736 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12737 { /*lint --e{715}*/
12738  assert(conshdlr != NULL);
12739  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12740  assert(consdata != NULL );
12741  assert(*consdata != NULL );
12742 
12743  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12744  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12745  {
12746  SCIP_CONSHDLRDATA* conshdlrdata;
12747 
12748  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12749  assert(conshdlrdata != NULL);
12750 
12751  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12752  }
12753 
12754  /* free cumulative constraint data */
12755  SCIP_CALL( consdataFree(scip, consdata) );
12756 
12757  return SCIP_OKAY;
12758 }
12759 
12760 /** transforms constraint data into data belonging to the transformed problem */
12761 static
12762 SCIP_DECL_CONSTRANS(consTransCumulative)
12763 { /*lint --e{715}*/
12764  SCIP_CONSHDLRDATA* conshdlrdata;
12765  SCIP_CONSDATA* sourcedata;
12766  SCIP_CONSDATA* targetdata;
12767 
12768  assert(conshdlr != NULL);
12769  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12770  assert(sourcecons != NULL);
12771  assert(targetcons != NULL);
12772 
12773  sourcedata = SCIPconsGetData(sourcecons);
12774  assert(sourcedata != NULL);
12775  assert(sourcedata->demandrows == NULL);
12776 
12777  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12778 
12779  /* get event handler */
12780  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12781  assert(conshdlrdata != NULL);
12782  assert(conshdlrdata->eventhdlr != NULL);
12783 
12784  /* create constraint data for target constraint */
12785  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12786  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12787  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12788 
12789  /* create target constraint */
12790  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12791  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12792  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12793  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12794  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12795 
12796  /* catch bound change events of variables */
12797  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12798 
12799  return SCIP_OKAY;
12800 }
12801 
12802 /** LP initialization method of constraint handler */
12803 static
12804 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12806  SCIP_CONSHDLRDATA* conshdlrdata;
12807  int c;
12808 
12809  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12810  assert(conshdlr != NULL);
12811  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12812  assert(conshdlrdata != NULL);
12813 
12814  *infeasible = FALSE;
12815 
12816  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12817 
12818  if( conshdlrdata->usebinvars )
12819  {
12820  /* add rows to LP */
12821  for( c = 0; c < nconss && !(*infeasible); ++c )
12822  {
12823  assert(SCIPconsIsInitial(conss[c]));
12824  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12825 
12826  if( conshdlrdata->cutsasconss )
12827  {
12828  SCIP_CALL( SCIPrestartSolve(scip) );
12829  }
12830  }
12831  }
12832 
12833  /**@todo if we want to use only the integer variables; only these will be in cuts
12834  * create some initial cuts, currently these are only separated */
12835 
12836  return SCIP_OKAY;
12837 }
12838 
12839 /** separation method of constraint handler for LP solutions */
12840 static
12841 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12843  SCIP_CONSHDLRDATA* conshdlrdata;
12844  SCIP_Bool cutoff;
12845  SCIP_Bool separated;
12846  int c;
12847 
12848  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12849 
12850  assert(conshdlr != NULL);
12851  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12852  assert(nconss == 0 || conss != NULL);
12853  assert(result != NULL);
12854  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12855  assert(conshdlrdata != NULL);
12856 
12857  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12858 
12859  cutoff = FALSE;
12860  separated = FALSE;
12861  (*result) = SCIP_DIDNOTRUN;
12862 
12863  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12864  return SCIP_OKAY;
12865 
12866  (*result) = SCIP_DIDNOTFIND;
12867 
12868  if( conshdlrdata->usebinvars )
12869  {
12870  /* check all useful cumulative constraints for feasibility */
12871  for( c = 0; c < nusefulconss && !cutoff; ++c )
12872  {
12873  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12874  }
12875 
12876  if( !cutoff && conshdlrdata->usecovercuts )
12877  {
12878  for( c = 0; c < nusefulconss; ++c )
12879  {
12880  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12881  }
12882  }
12883  }
12884 
12885  if( conshdlrdata->sepaold )
12886  {
12887  /* separate cuts containing only integer variables */
12888  for( c = 0; c < nusefulconss; ++c )
12889  {
12890  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12891  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12892  }
12893  }
12894 
12895  if( cutoff )
12896  *result = SCIP_CUTOFF;
12897  else if( separated )
12898  *result = SCIP_SEPARATED;
12899 
12900  return SCIP_OKAY;
12901 }
12902 
12903 /** separation method of constraint handler for arbitrary primal solutions */
12904 static
12905 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12906 { /*lint --e{715}*/
12907  SCIP_CONSHDLRDATA* conshdlrdata;
12908  SCIP_Bool cutoff;
12909  SCIP_Bool separated;
12910  int c;
12911 
12912  assert(conshdlr != NULL);
12913  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12914  assert(nconss == 0 || conss != NULL);
12915  assert(result != NULL);
12916 
12917  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12918  assert(conshdlrdata != NULL);
12919 
12920  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12921  return SCIP_OKAY;
12922 
12923  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12924 
12925  cutoff = FALSE;
12926  separated = FALSE;
12927  (*result) = SCIP_DIDNOTFIND;
12928 
12929  if( conshdlrdata->usebinvars )
12930  {
12931  /* check all useful cumulative constraints for feasibility */
12932  for( c = 0; c < nusefulconss && !cutoff; ++c )
12933  {
12934  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12935  }
12936 
12937  if( !cutoff && conshdlrdata->usecovercuts )
12938  {
12939  for( c = 0; c < nusefulconss; ++c )
12940  {
12941  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12942  }
12943  }
12944  }
12945  if( conshdlrdata->sepaold )
12946  {
12947  /* separate cuts containing only integer variables */
12948  for( c = 0; c < nusefulconss; ++c )
12949  {
12950  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12951  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12952  }
12953  }
12954 
12955  if( cutoff )
12956  *result = SCIP_CUTOFF;
12957  else if( separated )
12958  *result = SCIP_SEPARATED;
12959 
12960  return SCIP_OKAY;
12961 }
12962 
12963 /** constraint enforcing method of constraint handler for LP solutions */
12964 static
12965 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12966 { /*lint --e{715}*/
12967  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12968 
12969  return SCIP_OKAY;
12970 }
12971 
12972 /** constraint enforcing method of constraint handler for relaxation solutions */
12973 static
12974 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12975 { /*lint --e{715}*/
12976  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12977 
12978  return SCIP_OKAY;
12979 }
12980 
12981 /** constraint enforcing method of constraint handler for pseudo solutions */
12982 static
12983 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12984 { /*lint --e{715}*/
12985  SCIP_CONSHDLRDATA* conshdlrdata;
12986 
12987  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
12988 
12989  assert(conshdlr != NULL);
12990  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12991  assert(nconss == 0 || conss != NULL);
12992  assert(result != NULL);
12993 
12994  if( objinfeasible )
12995  {
12996  *result = SCIP_DIDNOTRUN;
12997  return SCIP_OKAY;
12998  }
12999 
13000  (*result) = SCIP_FEASIBLE;
13001 
13002  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13003  assert(conshdlrdata != NULL);
13004 
13005  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13006 
13007  return SCIP_OKAY;
13008 }
13009 
13010 /** feasibility check method of constraint handler for integral solutions */
13011 static
13012 SCIP_DECL_CONSCHECK(consCheckCumulative)
13013 { /*lint --e{715}*/
13014  int c;
13015 
13016  assert(conshdlr != NULL);
13017  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13018  assert(nconss == 0 || conss != NULL);
13019  assert(result != NULL);
13020 
13021  *result = SCIP_FEASIBLE;
13022 
13023  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13024 
13025  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13026  {
13027  SCIP_Bool violated = FALSE;
13028 
13029  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13030 
13031  if( violated )
13032  *result = SCIP_INFEASIBLE;
13033  }
13034 
13035  return SCIP_OKAY;
13036 }
13037 
13038 /** domain propagation method of constraint handler */
13039 static
13040 SCIP_DECL_CONSPROP(consPropCumulative)
13041 { /*lint --e{715}*/
13042  SCIP_CONSHDLRDATA* conshdlrdata;
13043  SCIP_Bool cutoff;
13044  int nchgbds;
13045  int ndelconss;
13046  int c;
13047 #if 0
13048  int naggrvars = 0;
13049 #endif
13050 
13051  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13052 
13053  assert(conshdlr != NULL);
13054  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13055  assert(nconss == 0 || conss != NULL);
13056  assert(result != NULL);
13057 
13058  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13059  assert(conshdlrdata != NULL);
13060 
13061  nchgbds = 0;
13062  ndelconss = 0;
13063  cutoff = FALSE;
13064  (*result) = SCIP_DIDNOTRUN;
13065 
13066  /* propgate all useful constraints */
13067  for( c = 0; c < nusefulconss && !cutoff; ++c )
13068  {
13069  SCIP_CONS* cons;
13070 
13071  cons = conss[c];
13072  assert(cons != NULL);
13073 
13074  if( SCIPgetDepth(scip) == 0 )
13075  {
13076 #if 0
13077  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13078  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13079 #else
13080  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13081  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13082 #endif
13083  if( cutoff )
13084  break;
13085 
13086  if( SCIPconsIsDeleted(cons) )
13087  continue;
13088  }
13089 
13090  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13091  }
13092 
13093  if( !cutoff && nchgbds == 0 )
13094  {
13095  /* propgate all other constraints */
13096  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13097  {
13098  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13099  }
13100  }
13101 
13102 #if 0
13103  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 )
13104  {
13105  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13106  }
13107 #endif
13108 
13109  if( cutoff )
13110  {
13111  SCIPdebugMsg(scip, "detected infeasible\n");
13112  *result = SCIP_CUTOFF;
13113  }
13114  else if( nchgbds > 0 )
13115  {
13116  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13117  *result = SCIP_REDUCEDDOM;
13118  }
13119  else
13120  *result = SCIP_DIDNOTFIND;
13121 
13122  return SCIP_OKAY;
13123 }
13124 
13125 /** presolving method of constraint handler */
13126 static
13127 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13128 { /*lint --e{715}*/
13129  SCIP_CONSHDLRDATA* conshdlrdata;
13130  SCIP_CONS* cons;
13131  SCIP_Bool cutoff;
13132  SCIP_Bool unbounded;
13133  int oldnfixedvars;
13134  int oldnchgbds;
13135  int oldndelconss;
13136  int oldnaddconss;
13137  int oldnupgdconss;
13138  int oldnchgsides;
13139  int oldnchgcoefs;
13140  int c;
13141 
13142  assert(conshdlr != NULL);
13143  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13144  assert(scip != NULL);
13145  assert(result != NULL);
13146 
13147  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13148 
13149  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13150  assert(conshdlrdata != NULL);
13151 
13152  *result = SCIP_DIDNOTRUN;
13153 
13154  oldnfixedvars = *nfixedvars;
13155  oldnchgbds = *nchgbds;
13156  oldnchgsides = *nchgsides;
13157  oldnchgcoefs = *nchgcoefs;
13158  oldnupgdconss = *nupgdconss;
13159  oldndelconss = *ndelconss;
13160  oldnaddconss = *naddconss;
13161  cutoff = FALSE;
13162  unbounded = FALSE;
13163 
13164  /* process constraints */
13165  for( c = 0; c < nconss && !cutoff; ++c )
13166  {
13167  cons = conss[c];
13168 
13169  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13170  * hmax)
13171  */
13172  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13173 
13174  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13175  {
13176 #if 0
13177  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13178  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13179 #else
13180  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13181  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13182 #endif
13183 
13184  if( cutoff || unbounded )
13185  break;
13186 
13187  if( SCIPconsIsDeleted(cons) )
13188  continue;
13189  }
13190 
13191  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13192  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13193  {
13194  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13195  }
13196 
13197  /* strengthen existing variable bounds using the cumulative condition */
13198  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13199  {
13200  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13201  }
13202 
13203  /* propagate cumulative constraint */
13204  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13205  assert(checkDemands(scip, cons) || cutoff);
13206  }
13207 
13208  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13209  {
13210  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, FALSE,
13211  nfixedvars, &cutoff, NULL) );
13212  }
13213 
13214  /* only perform the detection of variable bounds and disjunctive constraint once */
13215  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13216  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13217  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13218  {
13219  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13220  * propagation
13221  */
13222  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13223  conshdlrdata->detectedredundant = TRUE;
13224  }
13225 
13226  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13227  {
13228  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13229  }
13230 
13231  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13232  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13233 
13234  if( cutoff )
13235  *result = SCIP_CUTOFF;
13236  else if( unbounded )
13237  *result = SCIP_UNBOUNDED;
13238  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13239  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13240  *result = SCIP_SUCCESS;
13241  else
13242  *result = SCIP_DIDNOTFIND;
13243 
13244  return SCIP_OKAY;
13245 }
13246 
13247 /** propagation conflict resolving method of constraint handler */
13248 static
13249 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13250 { /*lint --e{715}*/
13251  SCIP_CONSHDLRDATA* conshdlrdata;
13252  SCIP_CONSDATA* consdata;
13253 
13254  assert(conshdlr != NULL);
13255  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13256  assert(scip != NULL);
13257  assert(result != NULL);
13258  assert(infervar != NULL);
13259  assert(bdchgidx != NULL);
13260 
13261  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13262  assert(conshdlrdata != NULL);
13263 
13264  /* process constraint */
13265  assert(cons != NULL);
13266 
13267  consdata = SCIPconsGetData(cons);
13268  assert(consdata != NULL);
13269 
13270  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13271  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13272  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13273 
13274  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13275  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13276  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13277 
13278  return SCIP_OKAY;
13279 }
13280 
13281 /** variable rounding lock method of constraint handler */
13282 static
13283 SCIP_DECL_CONSLOCK(consLockCumulative)
13284 { /*lint --e{715}*/
13285  SCIP_CONSDATA* consdata;
13286  SCIP_VAR** vars;
13287  int v;
13288 
13289  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13290 
13291  assert(scip != NULL);
13292  assert(cons != NULL);
13293  assert(locktype == SCIP_LOCKTYPE_MODEL);
13294 
13295  consdata = SCIPconsGetData(cons);
13296  assert(consdata != NULL);
13297 
13298  vars = consdata->vars;
13299  assert(vars != NULL);
13300 
13301  for( v = 0; v < consdata->nvars; ++v )
13302  {
13303  if( consdata->downlocks[v] && consdata->uplocks[v] )
13304  {
13305  /* the integer start variable should not get rounded in both direction */
13306  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13307  }
13308  else if( consdata->downlocks[v] )
13309  {
13310  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13311  }
13312  else if( consdata->uplocks[v] )
13313  {
13314  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13315  }
13316  }
13317 
13318  return SCIP_OKAY;
13319 }
13320 
13321 
13322 /** constraint display method of constraint handler */
13323 static
13324 SCIP_DECL_CONSPRINT(consPrintCumulative)
13325 { /*lint --e{715}*/
13326  assert(scip != NULL);
13327  assert(conshdlr != NULL);
13328  assert(cons != NULL);
13329 
13330  consdataPrint(scip, SCIPconsGetData(cons), file);
13331 
13332  return SCIP_OKAY;
13333 }
13334 
13335 /** constraint copying method of constraint handler */
13336 static
13337 SCIP_DECL_CONSCOPY(consCopyCumulative)
13338 { /*lint --e{715}*/
13339  SCIP_CONSDATA* sourceconsdata;
13340  SCIP_VAR** sourcevars;
13341  SCIP_VAR** vars;
13342  const char* consname;
13343 
13344  int nvars;
13345  int v;
13346 
13347  sourceconsdata = SCIPconsGetData(sourcecons);
13348  assert(sourceconsdata != NULL);
13349 
13350  /* get variables of the source constraint */
13351  nvars = sourceconsdata->nvars;
13352  sourcevars = sourceconsdata->vars;
13353 
13354  (*valid) = TRUE;
13355 
13356  if( nvars == 0 )
13357  return SCIP_OKAY;
13358 
13359  /* allocate buffer array */
13360  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13361 
13362  for( v = 0; v < nvars && *valid; ++v )
13363  {
13364  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13365  assert(!(*valid) || vars[v] != NULL);
13366  }
13367 
13368  /* only create the target constraint, if all variables could be copied */
13369  if( *valid )
13370  {
13371  if( name != NULL )
13372  consname = name;
13373  else
13374  consname = SCIPconsGetName(sourcecons);
13375 
13376  /* create a copy of the cumulative constraint */
13377  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13378  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13379  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13380 
13381  /* adjust left side if the time axis if needed */
13382  if( sourceconsdata->hmin > 0 )
13383  {
13384  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13385  }
13386 
13387  /* adjust right side if the time axis if needed */
13388  if( sourceconsdata->hmax < INT_MAX )
13389  {
13390  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13391  }
13392  }
13393 
13394  /* free buffer array */
13395  SCIPfreeBufferArray(scip, &vars);
13396 
13397  return SCIP_OKAY;
13398 }
13399 
13400 
13401 /** constraint parsing method of constraint handler */
13402 static
13403 SCIP_DECL_CONSPARSE(consParseCumulative)
13404 { /*lint --e{715}*/
13405  SCIP_VAR** vars;
13406  SCIP_VAR* var;
13407  SCIP_Real value;
13408  char strvalue[SCIP_MAXSTRLEN];
13409  char* endptr;
13410  int* demands;
13411  int* durations;
13412  int capacity;
13413  int duration;
13414  int demand;
13415  int hmin;
13416  int hmax;
13417  int varssize;
13418  int nvars;
13419 
13420  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13421 
13422  /* cutoff "cumulative" form the constraint string */
13423  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13424  str = endptr;
13425 
13426  varssize = 100;
13427  nvars = 0;
13428 
13429  /* allocate buffer array for variables */
13430  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13431  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13432  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13433 
13434  do
13435  {
13436  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13437 
13438  if( var != NULL )
13439  {
13440  str = endptr;
13441 
13442  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13443  duration = atoi(strvalue);
13444  str = endptr;
13445 
13446  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13447  demand = atoi(strvalue);
13448  str = endptr;
13449 
13450  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13451 
13452  vars[nvars] = var;
13453  demands[nvars] = demand;
13454  durations[nvars] = duration;
13455  nvars++;
13456  }
13457  }
13458  while( var != NULL );
13459 
13460  /* parse effective time window */
13461  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13462  hmin = atoi(strvalue);
13463  str = endptr;
13464 
13465  if( SCIPstrToRealValue(str, &value, &endptr) )
13466  {
13467  hmax = (int)(value);
13468  str = endptr;
13469 
13470  /* parse capacity */
13471  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13472  str = endptr;
13473  if( SCIPstrToRealValue(str, &value, &endptr) )
13474  {
13475  capacity = (int)value;
13476 
13477  /* create cumulative constraint */
13478  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13479  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13480 
13481  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13482  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13483 
13484  (*success) = TRUE;
13485  }
13486  }
13487 
13488  /* free buffer arrays */
13489  SCIPfreeBufferArray(scip, &durations);
13490  SCIPfreeBufferArray(scip, &demands);
13491  SCIPfreeBufferArray(scip, &vars);
13492 
13493  return SCIP_OKAY;
13494 }
13495 
13496 /** constraint method of constraint handler which returns the variables (if possible) */
13497 static
13498 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13499 { /*lint --e{715}*/
13500  SCIP_CONSDATA* consdata;
13501 
13502  consdata = SCIPconsGetData(cons);
13503  assert(consdata != NULL);
13504 
13505  if( varssize < consdata->nvars )
13506  (*success) = FALSE;
13507  else
13508  {
13509  assert(vars != NULL);
13510 
13511  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13512  (*success) = TRUE;
13513  }
13514 
13515  return SCIP_OKAY;
13516 }
13517 
13518 /** constraint method of constraint handler which returns the number of variables (if possible) */
13519 static
13520 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13521 { /*lint --e{715}*/
13522  SCIP_CONSDATA* consdata;
13523 
13524  consdata = SCIPconsGetData(cons);
13525  assert(consdata != NULL);
13526 
13527  (*nvars) = consdata->nvars;
13528  (*success) = TRUE;
13529 
13530  return SCIP_OKAY;
13531 }
13532 
13533 /**@} */
13534 
13535 /**@name Callback methods of event handler
13536  *
13537  * @{
13538  */
13539 
13540 
13541 /** execution method of event handler */
13542 static
13543 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13544 { /*lint --e{715}*/
13545  SCIP_CONSDATA* consdata;
13546 
13547  assert(scip != NULL);
13548  assert(eventhdlr != NULL);
13549  assert(eventdata != NULL);
13550  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13551  assert(event != NULL);
13552 
13553  consdata = (SCIP_CONSDATA*)eventdata;
13554  assert(consdata != NULL);
13555 
13556  /* mark the constraint to be not propagated */
13557  consdata->propagated = FALSE;
13558 
13559  return SCIP_OKAY;
13560 }
13561 
13562 /**@} */
13563 
13564 /**@name Interface methods
13565  *
13566  * @{
13567  */
13568 
13569 /*
13570  * constraint specific interface methods
13571  */
13572 
13573 /** creates the handler for cumulative constraints and includes it in SCIP */
13575  SCIP* scip /**< SCIP data structure */
13576  )
13577 {
13578  SCIP_CONSHDLRDATA* conshdlrdata;
13579  SCIP_CONSHDLR* conshdlr;
13580  SCIP_EVENTHDLR* eventhdlr;
13581 
13582  /* create event handler for bound change events */
13583  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13584 
13585  /* create cumulative constraint handler data */
13586  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13587 
13588  /* include constraint handler */
13591  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13592  conshdlrdata) );
13593 
13594  assert(conshdlr != NULL);
13595 
13596  /* set non-fundamental callbacks via specific setter functions */
13597  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13598  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13599 #ifdef SCIP_STATISTIC
13600  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13601 #endif
13602  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13603  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13604  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13605  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13606  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13607  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13608  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13609  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13611  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13612  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13614  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13615  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13617  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13618  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13619 
13620  /* add cumulative constraint handler parameters */
13622  "constraints/" CONSHDLR_NAME "/ttinfer",
13623  "should time-table (core-times) propagator be used to infer bounds?",
13624  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13626  "constraints/" CONSHDLR_NAME "/efcheck",
13627  "should edge-finding be used to detect an overload?",
13628  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13630  "constraints/" CONSHDLR_NAME "/efinfer",
13631  "should edge-finding be used to infer bounds?",
13632  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13634  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13635  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13637  "constraints/" CONSHDLR_NAME "/ttefcheck",
13638  "should time-table edge-finding be used to detect an overload?",
13639  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13641  "constraints/" CONSHDLR_NAME "/ttefinfer",
13642  "should time-table edge-finding be used to infer bounds?",
13643  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13644 
13646  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13647  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13649  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13650  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13652  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13653  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13655  "constraints/" CONSHDLR_NAME "/cutsasconss",
13656  "should the cumulative constraint create cuts as knapsack constraints?",
13657  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13659  "constraints/" CONSHDLR_NAME "/sepaold",
13660  "shall old sepa algo be applied?",
13661  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13662 
13664  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13665  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13666 
13667  /* presolving parameters */
13669  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13670  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13672  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13673  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13675  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13676  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13678  "constraints/" CONSHDLR_NAME "/presolpairwise",
13679  "should pairwise constraint comparison be performed in presolving?",
13680  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13682  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13683  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13684 
13686  "constraints/" CONSHDLR_NAME "/maxnodes",
13687  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13688  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13690  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13691  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13693  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13694  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13695 
13696  /* conflict analysis parameters */
13698  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13699  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13700 
13701  return SCIP_OKAY;
13702 }
13703 
13704 /** creates and captures a cumulative constraint */
13706  SCIP* scip, /**< SCIP data structure */
13707  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13708  const char* name, /**< name of constraint */
13709  int nvars, /**< number of variables (jobs) */
13710  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13711  int* durations, /**< array containing corresponding durations */
13712  int* demands, /**< array containing corresponding demands */
13713  int capacity, /**< available cumulative capacity */
13714  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13715  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13716  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13717  * Usually set to TRUE. */
13718  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13719  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13720  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13721  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13722  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13723  * Usually set to TRUE. */
13724  SCIP_Bool local, /**< is constraint only valid locally?
13725  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13726  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13727  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13728  * adds coefficients to this constraint. */
13729  SCIP_Bool dynamic, /**< is constraint subject to aging?
13730  * Usually set to FALSE. Set to TRUE for own cuts which
13731  * are seperated as constraints. */
13732  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13733  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13734  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13735  * if it may be moved to a more global node?
13736  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13737  )
13738 {
13739  SCIP_CONSHDLR* conshdlr;
13740  SCIP_CONSDATA* consdata;
13741 
13742  assert(scip != NULL);
13743 
13744  /* find the cumulative constraint handler */
13745  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13746  if( conshdlr == NULL )
13747  {
13748  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13749  return SCIP_PLUGINNOTFOUND;
13750  }
13751 
13752  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13753 
13754  /* create constraint data */
13755  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13756 
13757  /* create constraint */
13758  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13759  initial, separate, enforce, check, propagate,
13760  local, modifiable, dynamic, removable, stickingatnode) );
13761 
13762  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13763  {
13764  SCIP_CONSHDLRDATA* conshdlrdata;
13765 
13766  /* get event handler */
13767  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13768  assert(conshdlrdata != NULL);
13769  assert(conshdlrdata->eventhdlr != NULL);
13770 
13771  /* catch bound change events of variables */
13772  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13773  }
13774 
13775  return SCIP_OKAY;
13776 }
13777 
13778 /** creates and captures a cumulative constraint
13779  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13780  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13781  *
13782  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13783  *
13784  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13785  */
13787  SCIP* scip, /**< SCIP data structure */
13788  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13789  const char* name, /**< name of constraint */
13790  int nvars, /**< number of variables (jobs) */
13791  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13792  int* durations, /**< array containing corresponding durations */
13793  int* demands, /**< array containing corresponding demands */
13794  int capacity /**< available cumulative capacity */
13795  )
13796 {
13797  assert(scip != NULL);
13798 
13799  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13800  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13801 
13802  return SCIP_OKAY;
13803 }
13804 
13805 /** set the left bound of the time axis to be considered (including hmin) */
13807  SCIP* scip, /**< SCIP data structure */
13808  SCIP_CONS* cons, /**< constraint data */
13809  int hmin /**< left bound of time axis to be considered */
13810  )
13811 {
13812  SCIP_CONSDATA* consdata;
13813  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13814  {
13815  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13816  return SCIP_INVALIDCALL;
13817  }
13818 
13819  consdata = SCIPconsGetData(cons);
13820  assert(consdata != NULL);
13821  assert(hmin >= 0);
13822  assert(hmin <= consdata->hmax);
13823 
13824  consdata->hmin = hmin;
13825 
13826  return SCIP_OKAY;
13827 }
13828 
13829 /** returns the left bound of the time axis to be considered */
13831  SCIP* scip, /**< SCIP data structure */
13832  SCIP_CONS* cons /**< constraint */
13833  )
13834 {
13835  SCIP_CONSDATA* consdata;
13836  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13837  {
13838  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13839  SCIPABORT();
13840  return 0; /*lint !e527*/
13841  }
13842 
13843  consdata = SCIPconsGetData(cons);
13844  assert(consdata != NULL);
13845 
13846  return consdata->hmin;
13847 }
13848 
13849 /** set the right bound of the time axis to be considered (not including hmax) */
13851  SCIP* scip, /**< SCIP data structure */
13852  SCIP_CONS* cons, /**< constraint data */
13853  int hmax /**< right bound of time axis to be considered */
13854  )
13855 {
13856  SCIP_CONSDATA* consdata;
13857  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13858  {
13859  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13860  SCIPABORT();
13861  return SCIP_INVALIDCALL; /*lint !e527*/
13862  }
13863 
13864  consdata = SCIPconsGetData(cons);
13865  assert(consdata != NULL);
13866  assert(hmax >= consdata->hmin);
13867 
13868  consdata->hmax = hmax;
13869 
13870  return SCIP_OKAY;
13871 }
13872 
13873 /** returns the right bound of the time axis to be considered */
13875  SCIP* scip, /**< SCIP data structure */
13876  SCIP_CONS* cons /**< constraint */
13877  )
13878 {
13879  SCIP_CONSDATA* consdata;
13880  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13881  {
13882  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13883  SCIPABORT();
13884  return 0; /*lint !e527*/
13885  }
13886 
13887  consdata = SCIPconsGetData(cons);
13888  assert(consdata != NULL);
13889 
13890  return consdata->hmax;
13891 }
13892 
13893 /** returns the activities of the cumulative constraint */
13895  SCIP* scip, /**< SCIP data structure */
13896  SCIP_CONS* cons /**< constraint data */
13897  )
13898 {
13899  SCIP_CONSDATA* consdata;
13900 
13901  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13902  {
13903  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13904  SCIPABORT();
13905  return NULL; /*lint !e527*/
13906  }
13907 
13908  consdata = SCIPconsGetData(cons);
13909  assert(consdata != NULL);
13910 
13911  return consdata->vars;
13912 }
13913 
13914 /** returns the activities of the cumulative constraint */
13916  SCIP* scip, /**< SCIP data structure */
13917  SCIP_CONS* cons /**< constraint data */
13918  )
13919 {
13920  SCIP_CONSDATA* consdata;
13921 
13922  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13923  {
13924  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13925  SCIPABORT();
13926  return -1; /*lint !e527*/
13927  }
13928 
13929  consdata = SCIPconsGetData(cons);
13930  assert(consdata != NULL);
13931 
13932  return consdata->nvars;
13933 }
13934 
13935 /** returns the capacity of the cumulative constraint */
13937  SCIP* scip, /**< SCIP data structure */
13938  SCIP_CONS* cons /**< constraint data */
13939  )
13940 {
13941  SCIP_CONSDATA* consdata;
13942 
13943  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13944  {
13945  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13946  SCIPABORT();
13947  return -1; /*lint !e527*/
13948  }
13949 
13950  consdata = SCIPconsGetData(cons);
13951  assert(consdata != NULL);
13952 
13953  return consdata->capacity;
13954 }
13955 
13956 /** returns the durations of the cumulative constraint */
13958  SCIP* scip, /**< SCIP data structure */
13959  SCIP_CONS* cons /**< constraint data */
13960  )
13961 {
13962  SCIP_CONSDATA* consdata;
13963 
13964  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13965  {
13966  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13967  SCIPABORT();
13968  return NULL; /*lint !e527*/
13969  }
13970 
13971  consdata = SCIPconsGetData(cons);
13972  assert(consdata != NULL);
13973 
13974  return consdata->durations;
13975 }
13976 
13977 /** returns the demands of the cumulative constraint */
13979  SCIP* scip, /**< SCIP data structure */
13980  SCIP_CONS* cons /**< constraint data */
13981  )
13982 {
13983  SCIP_CONSDATA* consdata;
13984 
13985  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13986  {
13987  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13988  SCIPABORT();
13989  return NULL; /*lint !e527*/
13990  }
13991 
13992  consdata = SCIPconsGetData(cons);
13993  assert(consdata != NULL);
13994 
13995  return consdata->demands;
13996 }
13997 
13998 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13999  * given solution is satisfied
14000  */
14002  SCIP* scip, /**< SCIP data structure */
14003  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14004  int nvars, /**< number of variables (jobs) */
14005  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14006  int* durations, /**< array containing corresponding durations */
14007  int* demands, /**< array containing corresponding demands */
14008  int capacity, /**< available cumulative capacity */
14009  int hmin, /**< left bound of time axis to be considered (including hmin) */
14010  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14011  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14012  SCIP_CONS* cons, /**< constraint which is checked */
14013  SCIP_Bool printreason /**< should the reason for the violation be printed? */
14014  )
14015 {
14016  assert(scip != NULL);
14017  assert(violated != NULL);
14018 
14019  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14020  violated, cons, printreason) );
14021 
14022  return SCIP_OKAY;
14023 }
14024 
14025 /** normalize cumulative condition */
14027  SCIP* scip, /**< SCIP data structure */
14028  int nvars, /**< number of start time variables (activities) */
14029  SCIP_VAR** vars, /**< array of start time variables */
14030  int* durations, /**< array of durations */
14031  int* demands, /**< array of demands */
14032  int* capacity, /**< pointer to store the changed cumulative capacity */
14033  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14034  int* nchgsides /**< pointer to count number of side changes */
14035  )
14036 {
14037  SCIP_CALL( normalizeCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14038  nchgcoefs, nchgsides) );
14039 
14040  return SCIP_OKAY;
14041 }
14042 
14043 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14045  SCIP* scip, /**< SCIP data structure */
14046  int nvars, /**< number of variables (jobs) */
14047  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14048  int* durations, /**< array containing corresponding durations */
14049  int* demands, /**< array containing corresponding demands */
14050  int capacity, /**< available cumulative capacity */
14051  int* hmin, /**< pointer to store the left bound of the effective horizon */
14052  int* hmax, /**< pointer to store the right bound of the effective horizon */
14053  int* split /**< point were the cumulative condition can be split */
14054  )
14055 {
14056  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14057  hmin, hmax, split) );
14058 
14059  return SCIP_OKAY;
14060 }
14061 
14062 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14064  SCIP* scip, /**< SCIP data structure */
14065  int nvars, /**< number of start time variables (activities) */
14066  SCIP_VAR** vars, /**< array of start time variables */
14067  int* durations, /**< array of durations */
14068  int hmin, /**< left bound of time axis to be considered */
14069  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14070  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14071  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14072  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14073  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14074  int* nfixedvars, /**< pointer to store the number of fixed variables */
14075  int* nchgsides, /**< pointer to store the number of changed sides */
14076  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14077  )
14078 {
14079  if( nvars <= 1 )
14080  return SCIP_OKAY;
14081 
14082  /* presolve constraint form the earlier start time point of view */
14083  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14084  irrelevants, nfixedvars, nchgsides, cutoff) );
14085 
14086  /* presolve constraint form the latest completion time point of view */
14087  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14088  irrelevants, nfixedvars, nchgsides, cutoff) );
14089 
14090  return SCIP_OKAY;
14091 }
14092 
14093 /** propagate the given cumulative condition */
14095  SCIP* scip, /**< SCIP data structure */
14096  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14097  int nvars, /**< number of variables (jobs) */
14098  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14099  int* durations, /**< array containing corresponding durations */
14100  int* demands, /**< array containing corresponding demands */
14101  int capacity, /**< available cumulative capacity */
14102  int hmin, /**< left bound of time axis to be considered (including hmin) */
14103  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14104  SCIP_CONS* cons, /**< constraint which gets propagated */
14105  int* nchgbds, /**< pointer to store the number of variable bound changes */
14106  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14107  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14108  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14109  )
14110 {
14111  SCIP_CONSHDLR* conshdlr;
14112  SCIP_CONSHDLRDATA* conshdlrdata;
14113  SCIP_Bool redundant;
14114 
14115  assert(scip != NULL);
14116  assert(cons != NULL);
14117  assert(initialized != NULL);
14118  assert(*initialized == FALSE);
14119  assert(cutoff != NULL);
14120  assert(*cutoff == FALSE);
14121 
14122  /* find the cumulative constraint handler */
14123  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14124  if( conshdlr == NULL )
14125  {
14126  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14127  return SCIP_PLUGINNOTFOUND;
14128  }
14129 
14130  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14131  assert(conshdlrdata != NULL);
14132 
14133  redundant = FALSE;
14134 
14135  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14136  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14137  nchgbds, &redundant, initialized, explanation, cutoff) );
14138 
14139  return SCIP_OKAY;
14140 }
14141 
14142 /** resolve propagation w.r.t. the cumulative condition */
14144  SCIP* scip, /**< SCIP data structure */
14145  int nvars, /**< number of start time variables (activities) */
14146  SCIP_VAR** vars, /**< array of start time variables */
14147  int* durations, /**< array of durations */
14148  int* demands, /**< array of demands */
14149  int capacity, /**< cumulative capacity */
14150  int hmin, /**< left bound of time axis to be considered (including hmin) */
14151  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14152  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14153  int inferinfo, /**< the user information */
14154  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14155  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14156  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14157  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14158  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14159  )
14160 {
14161  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14162  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14163 
14164  return SCIP_OKAY;
14165 }
14166 
14167 /** this method visualizes the cumulative structure in GML format */
14169  SCIP* scip, /**< SCIP data structure */
14170  SCIP_CONS* cons /**< cumulative constraint */
14171  )
14172 {
14173  SCIP_CONSDATA* consdata;
14174  SCIP_HASHTABLE* vars;
14175  FILE* file;
14176  SCIP_VAR* var;
14177  char filename[SCIP_MAXSTRLEN];
14178  int nvars;
14179  int v;
14180 
14181  SCIP_RETCODE retcode = SCIP_OKAY;
14182 
14183  /* open file */
14184  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14185  file = fopen(filename, "w");
14186 
14187  /* check if the file was open */
14188  if( file == NULL )
14189  {
14190  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14191  SCIPprintSysError(filename);
14192  return SCIP_FILECREATEERROR;
14193  }
14194 
14195  consdata = SCIPconsGetData(cons);
14196  assert(consdata != NULL);
14197 
14198  nvars = consdata->nvars;
14199 
14200  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14201  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14202 
14203  /* create opening of the GML format */
14204  SCIPgmlWriteOpening(file, TRUE);
14205 
14206  for( v = 0; v < nvars; ++v )
14207  {
14208  char color[SCIP_MAXSTRLEN];
14209 
14210  var = consdata->vars[v];
14211  assert(var != NULL);
14212 
14213  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14214 
14215  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14216  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14217  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14218  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14219  else
14220  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14221 
14222  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14223  }
14224 
14225  for( v = 0; v < nvars; ++v )
14226  {
14227  SCIP_VAR** vbdvars;
14228  int nvbdvars;
14229  int b;
14230 
14231  var = consdata->vars[v];
14232  assert(var != NULL);
14233 
14234  vbdvars = SCIPvarGetVlbVars(var);
14235  nvbdvars = SCIPvarGetNVlbs(var);
14236 
14237  for( b = 0; b < nvbdvars; ++b )
14238  {
14239  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14240  {
14241  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14242  }
14243  }
14244 
14245 #if 0
14246  vbdvars = SCIPvarGetVubVars(var);
14247  nvbdvars = SCIPvarGetNVubs(var);
14248 
14249  for( b = 0; b < nvbdvars; ++b )
14250  {
14251  if( SCIPhashtableExists(vars, vbdvars[b]) )
14252  {
14253  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14254  }
14255  }
14256 #endif
14257  }
14258 
14259  /* create closing of the GML format */
14260  SCIPgmlWriteClosing(file);
14261 TERMINATE:
14262  /* close file */
14263  fclose(file);
14264 
14265  SCIPhashtableFree(&vars);
14266 
14267  return retcode;
14268 }
14269 
14270 /** sets method to solve an individual cumulative condition */
14272  SCIP* scip, /**< SCIP data structure */
14273  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14274  )
14275 {
14276  SCIP_CONSHDLR* conshdlr;
14277  SCIP_CONSHDLRDATA* conshdlrdata;
14278 
14279  /* find the cumulative constraint handler */
14280  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14281  if( conshdlr == NULL )
14282  {
14283  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14284  return SCIP_PLUGINNOTFOUND;
14285  }
14286 
14287  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14288  assert(conshdlrdata != NULL);
14289 
14290  conshdlrdata->solveCumulative = solveCumulative;
14291 
14292  return SCIP_OKAY;
14293 }
14294 
14295 /** solves given cumulative condition as independent sub problem
14296  *
14297  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14298  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14299  * solver was interrupted.
14300  */
14302  SCIP* scip, /**< SCIP data structure */
14303  int njobs, /**< number of jobs (activities) */
14304  SCIP_Real* ests, /**< array with the earlier start time for each job */
14305  SCIP_Real* lsts, /**< array with the latest start time for each job */
14306  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14307  int* durations, /**< array of durations */
14308  int* demands, /**< array of demands */
14309  int capacity, /**< cumulative capacity */
14310  int hmin, /**< left bound of time axis to be considered (including hmin) */
14311  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14312  SCIP_Real timelimit, /**< time limit for solving in seconds */
14313  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14314  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14315  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14316  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14317  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14318  SCIP_Bool* error /**< pointer to store if an error occurred */
14319  )
14320 {
14321  SCIP_CONSHDLR* conshdlr;
14322  SCIP_CONSHDLRDATA* conshdlrdata;
14323 
14324  (*solved) = TRUE;
14325  (*infeasible) = FALSE;
14326  (*unbounded) = FALSE;
14327  (*error) = FALSE;
14328 
14329  if( njobs == 0 )
14330  return SCIP_OKAY;
14331 
14332  /* find the cumulative constraint handler */
14333  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14334  if( conshdlr == NULL )
14335  {
14336  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14337  (*error) = TRUE;
14338  return SCIP_PLUGINNOTFOUND;
14339  }
14340 
14341  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14342  assert(conshdlrdata != NULL);
14343 
14344  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14345  if( timelimit > 0.0 && memorylimit > 10 )
14346  {
14347  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14348  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14349  }
14350 
14351  return SCIP_OKAY;
14352 }
14353 
14354 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14355  * completion time
14356  */
14358  SCIP* scip, /**< SCIP data structure */
14359  SCIP_PROFILE* profile, /**< resource profile */
14360  int nvars, /**< number of variables (jobs) */
14361  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14362  int* durations, /**< array containing corresponding durations */
14363  int* demands /**< array containing corresponding demands */
14364  )
14365 {
14366  SCIP_VAR* var;
14367  SCIP_HASHMAP* addedvars;
14368  int* copydemands;
14369  int* perm;
14370  int duration;
14371  int impliedest;
14372  int est;
14373  int impliedlct;
14374  int lct;
14375  int v;
14376 
14377  /* create hash map for variables which are added, mapping to their duration */
14378  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14379 
14380  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14381  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14382 
14383  /* sort variables w.r.t. job demands */
14384  for( v = 0; v < nvars; ++v )
14385  {
14386  copydemands[v] = demands[v];
14387  perm[v] = v;
14388  }
14389  SCIPsortDownIntInt(copydemands, perm, nvars);
14390 
14391  /* add each job with its earliest start and latest completion time into the resource profile */
14392  for( v = 0; v < nvars; ++v )
14393  {
14394  int idx;
14395 
14396  idx = perm[v];
14397  assert(idx >= 0 && idx < nvars);
14398 
14399  var = vars[idx];
14400  assert(var != NULL);
14401 
14402  duration = durations[idx];
14403  assert(duration > 0);
14404 
14405  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14406  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14407 
14408  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14409  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14410 
14411  if( impliedest < impliedlct )
14412  {
14413  SCIP_Bool infeasible;
14414  int pos;
14415 
14416  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14417  assert(!infeasible);
14418  assert(pos == -1);
14419  }
14420 
14421  if( est == impliedest && lct == impliedlct )
14422  {
14423  SCIP_CALL( SCIPhashmapInsert(addedvars, (void*)var, (void*)(size_t)duration) );
14424  }
14425  }
14426 
14427  SCIPfreeBufferArray(scip, &copydemands);
14428  SCIPfreeBufferArray(scip, &perm);
14429 
14430  SCIPhashmapFree(&addedvars);
14431 
14432  return SCIP_OKAY;
14433 }
14434 
14435 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */
14436 int SCIPcomputeHmin(
14437  SCIP* scip, /**< SCIP data structure */
14438  SCIP_PROFILE* profile, /**< worst case resource profile */
14439  int capacity /**< capacity to check */
14440  )
14441 {
14442  int* timepoints;
14443  int* loads;
14444  int ntimepoints;
14445  int t;
14446 
14447  ntimepoints = SCIPprofileGetNTimepoints(profile);
14448  timepoints = SCIPprofileGetTimepoints(profile);
14449  loads = SCIPprofileGetLoads(profile);
14450 
14451  /* find first time point which potentially violates the capacity restriction */
14452  for( t = 0; t < ntimepoints - 1; ++t )
14453  {
14454  /* check if the time point exceed w.r.t. worst case profile the capacity */
14455  if( loads[t] > capacity )
14456  {
14457  assert(t == 0 || loads[t-1] <= capacity);
14458  return timepoints[t];
14459  }
14460  }
14461 
14462  return INT_MAX;
14463 }
14464 
14465 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */
14466 int SCIPcomputeHmax(
14467  SCIP* scip, /**< SCIP data structure */
14468  SCIP_PROFILE* profile, /**< worst case profile */
14469  int capacity /**< capacity to check */
14470  )
14471 {
14472  int* timepoints;
14473  int* loads;
14474  int ntimepoints;
14475  int t;
14476 
14477  ntimepoints = SCIPprofileGetNTimepoints(profile);
14478  timepoints = SCIPprofileGetTimepoints(profile);
14479  loads = SCIPprofileGetLoads(profile);
14480 
14481  /* find last time point which potentially violates the capacity restriction */
14482  for( t = ntimepoints - 1; t >= 0; --t )
14483  {
14484  /* check if at time point t the worst case resource profile exceeds the capacity */
14485  if( loads[t] > capacity )
14486  {
14487  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14488  return timepoints[t+1];
14489  }
14490  }
14491 
14492  return INT_MIN;
14493 }
14494 
14495 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
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:8010
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:116
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4221
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3236
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:105
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8074
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:640
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:213
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:436
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17557
static SCIP_DECL_CONSCOPY(consCopyCumulative)
#define NULL
Definition: def.h:239
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:59
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:99
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:5120
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1547
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2130
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3176
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9227
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:412
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:8335
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:663
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:6573
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:1994
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8119
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1033
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2265
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:40
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:422
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:954
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1570
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17535
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:17343
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:893
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:379
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:260
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3233
#define DEFAULT_MAXNODES
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16930
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:627
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:385
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1826
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
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:2895
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:210
static long bound
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1602
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:17399
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:393
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_PROP_TIMING
int * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
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:172
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:485
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1538
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:523
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:6370
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1251
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:554
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower)
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:687
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip_cons.c:1639
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:9645
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:8280
static SCIP_Bool isConsIndependently(SCIP *scip, SCIP_CONS *cons)
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:65
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:2793
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:314
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:183
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10325
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:243
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:10017
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:64
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
enum Proprule PROPRULE
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 SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *intvar)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8355
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17577
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
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:17036
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:184
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:8385
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:5236
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:114
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:6543
#define SCIPdebugMessage
Definition: pub_message.h:77
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:297
#define CONSHDLR_DELAYPROP
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17547
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:171
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:138
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:2931
#define DEFAULT_COEFTIGHTENING
static SCIP_RETCODE createNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
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:6572
#define SCIP_LONGINT_MAX
Definition: def.h:136
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:142
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:339
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16940
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:97
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:611
#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:694
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8345
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:686
#define SCIPdebugMsgPrint
Definition: scip_message.h:89
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6382
#define SCIPdebugMsg
Definition: scip_message.h:88
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1483
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:870
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8137
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:279
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:1011
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:223
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
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 SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8179
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 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:2014
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)
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 void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_DESC
#define MIN3(x, y, z)
Definition: def.h:214
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17080
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4199
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
static SCIP_RETCODE updateEnvelop(SCIP *scip, SCIP_BTNODE *node)
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:1310
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_DECL_CONSCHECK(consCheckCumulative)
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17353
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:111
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:74
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_PRESOLTIMING
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2577
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:409
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:8129
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, int energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4191
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2822
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
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)
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:3527
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8266
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)
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:128
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1796
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:143
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:520
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:519
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:128
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:10148
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4375
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:8076
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:17609
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8514
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8295
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16729
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:434
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4211
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)
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)
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 int computeTotalEnergy(int *durations, int *demands, int njobs)
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)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:351
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17567
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)
void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
#define SCIPstatisticPrintf
Definition: pub_message.h:107
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip_param.c:951
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6278
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17599
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8315
Definition: grphload.c:88
#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:1152
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:294
#define DEFAULT_DETECTDISJUNCTIVE
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:709
static SCIP_DECL_CONSFREE(consFreeCumulative)
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8217
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:51
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:8402
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)
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 an integer variable
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8149
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:130
#define SCIP_UNKNOWN
Definition: def.h:171
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:62
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:9926
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1336
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:715
#define DEFAULT_USECOVERCUTS
static void freeNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6396
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2550
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:165
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10118
static SCIP_RETCODE normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE computeCoreEngeryAfter(SCIP *scip, SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8096
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11422
#define MIN(x, y)
Definition: def.h:209
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:578
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8310
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8205
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 createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8199
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17191
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:468
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:104
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:654
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:49
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8168
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
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:4290
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6308
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:847
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
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:6350
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:5416
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_DECL_SORTINDCOMP(consdataCompVar)
Proprule
#define DEFAULT_FILLBRANCHCANDS
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6360
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:152
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip_param.c:752
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:8392
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2044
#define DEFAULT_DETECTVARBOUNDS
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)
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8139
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:50
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)
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, int energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
#define SCIP_LONGINT_FORMAT
Definition: def.h:142
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:578
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1474
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:8415
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3041
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *intvar, SCIP_VAR **binvars, int *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 SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:140
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA **nodedatas, int *nnodedatas)
#define MAX(x, y)
Definition: def.h:208
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
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8252
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)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5081
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2379
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:171
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:737
static SCIP_DECL_CONSPRINT(consPrintCumulative)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1724
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8106
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:5529
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3465
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:1335
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3094
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1187
#define DEFAULT_CUTSASCONSS
static int computeCoreWithInterval(int begin, int end, int ect, int lst)
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip_var.c:8478
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:602
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:322
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1911
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:197
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1999
static SCIP_RETCODE normalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16848
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
#define SCIPstatistic(x)
Definition: pub_message.h:101
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:8277
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:150
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8325
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:739
static SCIP_DECL_CONSTRANS(consTransCumulative)
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:916
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:372
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:8265
#define SCIP_INVALID
Definition: def.h:170
#define EVENTHDLR_DESC
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8255
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2094
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17589
#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:135
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17026
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:2068
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16894
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2377
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
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)
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:50
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated)
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)
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
#define nnodes
Definition: gastrans.c:65
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17409
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:117
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:671
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_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16871
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *intvar)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
#define DEFAULT_USEBDWIDENING
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:9096
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:9619
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8291
static SCIP_RETCODE collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
int TCLIQUE_WEIGHT
Definition: tclique.h:39
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:6340
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:530
#define SCIPABORT()
Definition: def.h:323
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:8454
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1410
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 SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip_param.c:973
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8189
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:636
static int inferInfoToInt(INFERINFO inferinfo)
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
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:129
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17016
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6292
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:371
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:134
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:343
#define DEFAULT_SEPAOLD
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1285